emacs/admin/grammars/c.by

1237 lines
30 KiB
Plaintext

;;; c.by -- LL grammar for C/C++ language specification
;; Copyright (C) 1999-2024 Free Software Foundation, Inc.
;;
;; Author: Eric M. Ludlam <zappo@gnu.org>
;; David Ponce <david@dponce.com>
;; Klaus Berndl <klaus.berndl@sdm.de>
;;
;; This file is part of GNU Emacs.
;; GNU Emacs is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; GNU Emacs is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;; TODO: From Nate Schley
;; > * Can't parse signature element: "const char* const rmc_ClrTxt"
;; > * Can't parse signature element: "char* const dellog_ClrTxt"
;; > * Can't parse signature element: "const char* dellog_SetTxt"
;; > * Can't parse signature element: "const RmcCmdSSPADetailedStatus& status"
;; >
;; > And FWIW I have seen the following argument cases not handled, even
;; > with no leading/trailing spaces in the split:
;; >
;; > * Can't parse signature element: "const bool currentAlarmStatus"
;; > * Can't parse signature element: "unsigned char mode"
;; > * Can't parse signature element: "TskTimingTask* tsktimingtask"
;; > * Can't parse signature element: "unsigned char htrStatus"
;; > * Can't parse signature element: "char trackPower[]"
;; > * Can't parse signature element: "const RmcCmdMCDetailedStatus& status"
;; > * Can't parse signature element: "RmcBucStatus* rftBucStatus"
%package semantic-c-by
%provide semantic/bovine/c-by
%{
(declare-function semantic-c-reconstitute-token "semantic/bovine/c"
(tokenpart declmods typedecl))
(declare-function semantic-c-reconstitute-template "semantic/bovine/c"
(tag specifier))
(declare-function semantic-expand-c-tag "semantic/bovine/c" (tag))
(declare-function semantic-parse-region "semantic"
(start end &optional nonterminal depth returnonerror))
}
%languagemode c-mode c++-mode
%start declaration
%scopestart codeblock
%token <punctuation> HASH "\\`[#]\\'"
%token <punctuation> PERIOD "\\`[.]\\'"
%token <punctuation> COLON "\\`[:]\\'"
%token <punctuation> SEMICOLON "\\`[;]\\'"
%token <punctuation> STAR "\\`[*]\\'"
%token <punctuation> AMPERSAND "\\`[&]\\'"
%token <punctuation> DIVIDE "\\`[/]\\'"
%token <punctuation> PLUS "\\`[+]\\'"
%token <punctuation> MINUS "\\`[-]\\'"
%token <punctuation> BANG "\\`[!]\\'"
%token <punctuation> QUESTION "\\`[?]\\'"
%token <punctuation> EQUAL "\\`[=]\\'"
%token <punctuation> LESS "\\`[<]\\'"
%token <punctuation> GREATER "\\`[>]\\'"
%token <punctuation> COMA "\\`[,]\\'"
%token <punctuation> TILDE "\\`[~]\\'"
%token <punctuation> MOD "\\`[%]\\'"
%token <punctuation> HAT "\\`\\^\\'"
%token <punctuation> OR "\\`[|]\\'"
%token <string> C "\"C\""
%token <string> CPP "\"C\\+\\+\""
%token <number> ZERO "^0$"
%token <symbol> RESTRICT "\\<\\(__\\)?restrict\\>"
%token <open-paren> LPAREN "("
%token <close-paren> RPAREN ")"
%token <open-paren> LBRACE "{"
%token <close-paren> RBRACE "}"
%token <semantic-list> BRACK_BLCK "\\[.*\\]$"
%token <semantic-list> PAREN_BLCK "^("
%token <semantic-list> BRACE_BLCK "^{"
%token <semantic-list> VOID_BLCK "^(void)$"
%token <semantic-list> PARENS "()"
%token <semantic-list> BRACKETS "\\[\\]"
%token EXTERN "extern"
%put EXTERN summary "Declaration Modifier: extern <type> <name> ..."
%token STATIC "static"
%put STATIC summary "Declaration Modifier: static <type> <name> ..."
%token CONST "const"
%put CONST summary "Declaration Modifier: const <type> <name> ..."
%token VOLATILE "volatile"
%put VOLATILE summary "Declaration Modifier: volatile <type> <name> ..."
%token REGISTER "register"
%put REGISTER summary "Declaration Modifier: register <type> <name> ..."
%token SIGNED "signed"
%put SIGNED summary "Numeric Type Modifier: signed <numeric type> <name> ..."
%token UNSIGNED "unsigned"
%put UNSIGNED summary "Numeric Type Modifier: unsigned <numeric type> <name> ..."
%token INLINE "inline"
%put INLINE summary "Function Modifier: inline <return type> <name>(...) {...};"
%token VIRTUAL "virtual"
%put VIRTUAL summary "Method Modifier: virtual <type> <name>(...) ..."
%token MUTABLE "mutable"
%put MUTABLE summary "Member Declaration Modifier: mutable <type> <name> ..."
%token EXPLICIT "explicit"
%put EXPLICIT summary "Forbids implicit type conversion: explicit <constructor>"
%token STRUCT "struct"
%put STRUCT summary "Structure Type Declaration: struct [name] { ... };"
%token UNION "union"
%put UNION summary "Union Type Declaration: union [name] { ... };"
%token ENUM "enum"
%put ENUM summary "Enumeration Type Declaration: enum [name] { ... };"
%token TYPEDEF "typedef"
%put TYPEDEF summary "Arbitrary Type Declaration: typedef <typedeclaration> <name>;"
%token CLASS "class"
%put CLASS summary "Class Declaration: class <name>[:parents] { ... };"
%token TYPENAME "typename"
%put TYPENAME summary "typename is used to handle a qualified name as a typename;"
%token NAMESPACE "namespace"
%put NAMESPACE summary "Namespace Declaration: namespace <name> { ... };"
%token USING "using"
%put USING summary "using <namespace>;"
%token NEW "new"
%put NEW summary "new <classname>();"
%token DELETE "delete"
%put DELETE summary "delete <object>;"
;; Despite this, this parser can find templates by ignoring the TEMPLATE
;; keyword, and finding the class/method being templatized.
%token TEMPLATE "template"
%put TEMPLATE summary "template <class TYPE ...> TYPE_OR_FUNCTION"
%token THROW "throw"
%put THROW summary "<type> <methoddef> (<method args>) throw (<exception>) ..."
%token REENTRANT "reentrant"
%put REENTRANT summary "<type> <methoddef> (<method args>) reentrant ..."
%token TRY "try"
%token CATCH "catch"
%put { TRY CATCH } summary "try { <body> } catch { <catch code> }"
;; Leave these alone for now.
%token OPERATOR "operator"
%token PUBLIC "public"
%token PRIVATE "private"
%token PROTECTED "protected"
%token FRIEND "friend"
%put FRIEND summary "friend class <CLASSNAME>"
;; These aren't used for parsing, but is a useful place to describe the keywords.
%token IF "if"
%token ELSE "else"
%put {IF ELSE} summary "if (<condition>) { code } [ else { code } ]"
%token DO "do"
%token WHILE "while"
%put DO summary " do { code } while (<condition>);"
%put WHILE summary "do { code } while (<condition>); or while (<condition>) { code };"
%token FOR "for"
%put FOR summary "for(<init>; <condition>; <increment>) { code }"
%token SWITCH "switch"
%token CASE "case"
%token DEFAULT "default"
%put {SWITCH CASE DEFAULT} summary
"switch (<variable>) { case <constvalue>: code; ... default: code; }"
%token RETURN "return"
%put RETURN summary "return <value>;"
%token BREAK "break"
%put BREAK summary "Non-local exit within a loop or switch (for, do/while, switch): break;"
%token CONTINUE "continue"
%put CONTINUE summary "Non-local continue within a loop (for, do/while): continue;"
%token SIZEOF "sizeof"
%put SIZEOF summary "Compile time macro: sizeof(<type or variable>) // size in bytes"
;; Types
%token VOID "void"
%put VOID summary "Built in type: void"
%token CHAR "char"
%put CHAR summary "Integral Character Type: (0 to 256)"
%token WCHAR "wchar_t"
%put WCHAR summary "Wide Character Type"
%token SHORT "short"
%put SHORT summary "Integral Primitive Type: (-32768 to 32767)"
%token INT "int"
%put INT summary "Integral Primitive Type: (-2147483648 to 2147483647)"
%token LONG "long"
%put LONG summary "Integral primitive type (-9223372036854775808 to 9223372036854775807)"
%token FLOAT "float"
%put FLOAT summary "Primitive floating-point type (single-precision 32-bit IEEE 754)"
%token DOUBLE "double"
%put DOUBLE summary "Primitive floating-point type (double-precision 64-bit IEEE 754)"
%token BOOL "bool"
%put BOOL summary "Primitive boolean type"
%token UNDERP "_P"
%token UNDERUNDERP "__P"
%put UNDERP summary "Common macro to eliminate prototype compatibility on some compilers"
%put UNDERUNDERP summary "Common macro to eliminate prototype compatibility on some compilers"
%%
declaration
: macro
| type
;; TODO: Klaus Berndl: Is the define here necessary or even wrong?
;; Is this part not already covered by macro??
| define
| var-or-fun
| extern-c
| template
| using
;
codeblock
: define
| codeblock-var-or-fun
| type ;; type is less likely to be used here.
| using
;
extern-c-contents
: open-paren
( nil )
| declaration
| close-paren
( nil )
;
extern-c
: EXTERN C semantic-list
;; Extern C commands which contain a list need to have the
;; entries of the list extracted, and spliced into the main
;; list of entries. This must be done via the function
;; that expands singular nonterminals, such as int x,y;
(TAG "C" 'extern :members (EXPANDFULL $3 extern-c-contents) )
| EXTERN CPP semantic-list
(TAG "C" 'extern :members (EXPANDFULL $3 extern-c-contents) )
| EXTERN C
;; A plain extern "C" call should add something to the token,
;; but just strip it from the buffer here for now.
( nil )
| EXTERN CPP
( nil )
;
macro
: spp-macro-def
(VARIABLE-TAG $1 nil nil :constant-flag t )
| spp-system-include
(INCLUDE-TAG $1 t)
| spp-include
(INCLUDE-TAG $1 nil)
;
;; This is used in struct parts.
define
: spp-macro-def
(VARIABLE-TAG $1 nil nil :constant-flag t)
| spp-macro-undef
( nil )
;
;; In C++, structures can have the same things as classes.
;; So delete this some day in the figure.
;;
;;structparts : semantic-list
;; (EXPANDFULL $1 structsubparts)
;; ;
;;
;;structsubparts : LBRACE
;; ( nil )
;; | RBRACE
;; ( nil )
;; | var-or-fun
;; | define
;; ;; sometimes there are defines in structs.
;; ;
unionparts
: semantic-list
(EXPANDFULL $1 classsubparts)
;
opt-symbol
: symbol
| ;;EMPTY
;
;; @todo - support 'friend' construct.
classsubparts
: LBRACE
( nil )
| RBRACE
( nil )
| class-protection opt-symbol COLON
;; For QT, they may put a `slot' keyword between the protection
;; and the COLON. @todo - Have the QT stuff use macros.
(TAG (car $1) 'label)
| var-or-fun
| FRIEND func-decl
(TAG (car $2) 'friend)
| FRIEND CLASS symbol
(TAG $3 'friend)
| type
| define
| template
| ;;EMPTY
;
opt-class-parents
: COLON class-parents opt-template-specifier
( $2 )
| ;;EMPTY
( )
;
one-class-parent
: opt-class-protection opt-class-declmods namespace-symbol
(TYPE-TAG (car $3) "class" nil nil :protection (car $1))
| opt-class-declmods opt-class-protection namespace-symbol
(TYPE-TAG (car $3) "class" nil nil :protection (car $2))
;
class-parents
: one-class-parent COMA class-parents
( ,(cons ,$1 $3 ) )
| one-class-parent
( $1 )
;
opt-class-declmods
: class-declmods opt-class-declmods
( nil )
| ;;EMPTY
;
class-declmods
: VIRTUAL
;
class-protection
: PUBLIC
| PRIVATE
| PROTECTED
;
opt-class-protection
: class-protection
( ,$1 )
| ;;EMPTY - Same as private
( "unspecified" )
;
namespaceparts
: semantic-list
(EXPANDFULL $1 namespacesubparts)
;
namespacesubparts
: LBRACE
( nil )
| RBRACE
( nil )
| type
| var-or-fun
| define
| class-protection COLON
(TAG (car $1) 'label)
;; In C++, this label in a classsubpart represents
;; PUBLIC or PRIVATE bits. Ignore them for now.
| template
| using
;; Includes inside namespaces
| spp-include
(TAG $1 'include :inside-ns t)
| ;;EMPTY
;
enumparts
: semantic-list
(EXPANDFULL $1 enumsubparts)
;
enumsubparts
: symbol opt-assign
(VARIABLE-TAG $1 "int" (car $2) :constant-flag t )
| LBRACE
( nil )
| RBRACE
( nil )
| COMA
( nil )
;
opt-name
: symbol
| ;;EMPTY
( "" )
;
typesimple
: struct-or-class opt-class opt-name opt-template-specifier
opt-class-parents semantic-list
(TYPE-TAG (car $3) (car $1)
(dlet ((semantic-c-classname (cons (car ,$3) (car ,$1))))
(EXPANDFULL $6 classsubparts))
$5
:template-specifier $4
:parent (car ,$2))
| struct-or-class opt-class opt-name opt-template-specifier
opt-class-parents
(TYPE-TAG (car $3) (car $1) nil $5
:template-specifier $4
:prototype t
:parent (car ,$2))
| UNION opt-class opt-name unionparts
(TYPE-TAG (car $3) $1 $4 nil
:parent (car ,$2))
| ENUM opt-class opt-name enumparts
(TYPE-TAG (car $3) $1 $4 nil
:parent (car ,$2))
;; Klaus Berndl: a typedef can be a typeformbase with all this
;; declmods stuff.
| TYPEDEF declmods typeformbase cv-declmods typedef-symbol-list
;;;; We put the type this typedef renames into PARENT
;;;; but will move it in the expand function.
(TYPE-TAG $5 $1 nil (list $3) )
;
typedef-symbol-list
: typedefname COMA typedef-symbol-list
( ,(cons $1 $3) )
| typedefname
( $1 )
;
;; TODO: Klaus Berndl: symbol -> namespace-symbol?! Answer: Probably
;; symbol is correct here!
typedefname
: opt-stars symbol opt-bits opt-array
( $1 $2 )
;
struct-or-class
: STRUCT
| CLASS
;
type
: typesimple SEMICOLON
( ,$1 )
;; named namespaces like "namespace XXX {"
| NAMESPACE symbol namespaceparts
(TYPE-TAG $2 $1 $3 nil )
;; unnamed namespaces like "namespace {"
| NAMESPACE namespaceparts
(TYPE-TAG "unnamed" $1 $2 nil )
;; David Engster: namespace alias like "namespace foo = bar;"
| NAMESPACE symbol EQUAL typeformbase SEMICOLON
(TYPE-TAG $2 $1 (list (TYPE-TAG (car $4) $1 nil nil)) nil :kind 'alias )
;
;; Klaus Berndl: We must parse "using namespace XXX" too
;; Using is vaguely like an include statement in the named portions
;; of the code. We should probably specify a new token type for this.
using
: USING usingname SEMICOLON
(TAG (car $2) 'using :type ,$2 )
;
;; Jan Moringen: Differentiate between 'using' and 'using namespace'
;; Adapted to creating type tags by EML.
usingname
: typeformbase
(TYPE-TAG (car $1) "class" nil nil :prototype t)
| NAMESPACE typeformbase
(TYPE-TAG (car $2) "namespace" nil nil :prototype t)
;
template
: TEMPLATE template-specifier opt-friend template-definition
( ,(semantic-c-reconstitute-template $4 ,$2) )
;
opt-friend
: FRIEND
| ;;EMPTY
;
opt-template-specifier
: template-specifier
( ,$1 )
| ;;EMPTY
( )
;
template-specifier
: LESS template-specifier-types GREATER
( ,$2 )
;
template-specifier-types
: template-var template-specifier-type-list
( ,(cons ,$1 ,$2 ) )
| ;;EMPTY
;
template-specifier-type-list
: COMA template-specifier-types
( ,$2 )
| ;;EMPTY
( )
;
;; template-var
;; : template-type opt-stars opt-template-equal
;; ( ,(cons (concat (car $1) (make-string (car ,$2) ?*))
;; (cdr $1)))
;; ;; Klaus Berndl: for template-types the template-var can also be
;; ;; literals or constants. Example: map<ClassX, ClassY, 10>
;; ;; map_size10_var; This parses also template<class T, 0> which is
;; ;; nonsense but who cares....
;; | string
;; ( $1 )
;; | number
;; ( $1 )
;; ;
template-var
:
;; Klaus Berndl: The following handles all template-vars of
;; template-definitions
template-type opt-template-equal
( ,(cons (car $1) (cdr $1)) )
;; Klaus Berndl: for template-types the template-var can also be
;; literals or constants.
;; Example: map<ClassX, ClassY, 10> map_size10_var; This parses also
;; template<class T, 0> which is nonsense but who cares....
| string
( $1 )
| number
( $1 )
;; Klaus Berndl: In template-types arguments can be any symbols with
;; optional address-operator (&) and optional dereferencing operator
;; (*). Example map<ClassX, ClassY, *size_var_ptr> sized_map_var.
| opt-stars opt-ref namespace-symbol
( ,$3 )
;; Some code can compile down into a number, but starts out as an
;; expression, such as "sizeof(a)", or (sizeof(a)/sizeof(b))
| semantic-list
( $1 )
| SIZEOF semantic-list
( $2 )
;
opt-template-equal
: EQUAL symbol LESS template-specifier-types GREATER
( $2 )
| EQUAL symbol
( $2 )
| ;;EMPTY
( )
;
template-type
: CLASS symbol
(TYPE-TAG $2 "class" nil nil )
| STRUCT symbol
(TYPE-TAG $2 "struct" nil nil )
;; TODO: Klaus Berndl: For the moment it is ok, that we parse the C++
;; keyword typename as a class....
| TYPENAME symbol
(TYPE-TAG $2 "class" nil nil)
;; Klaus Berndl: template-types can be all flavors of variable-args
;; but here the argument is ignored, only the type stuff is needed.
| declmods typeformbase cv-declmods opt-stars
opt-ref variablearg-opt-name
(TYPE-TAG (car $2) nil nil nil
:template-specifier (plist-get (nth 2 $2) :template-specifier)
:constant-flag (if (member "const" (append $1 $3)) t nil)
:typemodifiers (delete "const" (append $1 $3))
:reference (car ,$5)
:pointer (car $4)
:typevar (car $6)
)
;
template-definition
: type
( ,$1 )
| var-or-fun
( ,$1 )
;
opt-stars
: STAR opt-starmod opt-stars
( (1+ (car $3)) )
| ;;EMPTY
( 0 )
;
opt-starmod
: STARMOD opt-starmod
( ,(cons (,car ,$1) $2) )
| ;;EMPTY
()
;
STARMOD
: CONST
;
declmods
: DECLMOD declmods
( ,(cons ,(car ,$1) $2 ) )
| DECLMOD
( ,$1 )
| ;;EMPTY
()
;
DECLMOD
: EXTERN
| STATIC
| CVDECLMOD
;; Klaus Berndl: IMHO signed and unsigned are not decl-modes but
;; these are only valid for some buildin-types like short, int
;; etc... whereas "real" declmods are valid for all types, buildin
;; and user-defined! SIGNED UNSIGNED
| INLINE
| REGISTER
| FRIEND
;; Klaus Berndl: There can be a few cases where TYPENAME is not
;; allowed in C++-syntax but better than not recognizing the allowed
;; situations.
| TYPENAME
| METADECLMOD
;; This is a hack in case we are in a class.
| VIRTUAL
;
metadeclmod
: METADECLMOD
()
| ;;EMPTY
()
;
CVDECLMOD
: CONST
| VOLATILE
;
cv-declmods
: CVDECLMOD cv-declmods
( ,(cons ,(car ,$1) $2 ) )
| CVDECLMOD
( ,$1 )
| ;;EMPTY
()
;
METADECLMOD
: VIRTUAL
| MUTABLE
;
;; C++: A type can be modified into a reference by "&"
opt-ref
: AMPERSAND
( 1 )
| ;;EMPTY
( 0 )
;
typeformbase
: typesimple
( ,$1 )
| STRUCT symbol
(TYPE-TAG $2 $1 nil nil )
| UNION symbol
(TYPE-TAG $2 $1 nil nil )
| ENUM symbol
(TYPE-TAG $2 $1 nil nil )
| builtintype
( ,$1 )
| symbol template-specifier
(TYPE-TAG $1 "class" nil nil :template-specifier $2)
;;| namespace-symbol opt-stars opt-template-specifier
;;| namespace-symbol opt-template-specifier
| namespace-symbol-for-typeformbase opt-template-specifier
(TYPE-TAG (car $1) "class" nil nil
:template-specifier $2)
| symbol
( $1 )
;
signedmod
: UNSIGNED
| SIGNED
;
;; Klaus Berndl: builtintype-types was builtintype
builtintype-types
: VOID
| CHAR
;; Klaus Berndl: Added WCHAR
| WCHAR
| SHORT INT
( (concat $1 " " $2) )
| SHORT
| INT
| LONG INT
( (concat $1 " " $2) )
| FLOAT
| DOUBLE
| BOOL
| LONG DOUBLE
( (concat $1 " " $2) )
;; TODO: Klaus Berndl: Is there a long long, i think so?!
| LONG LONG
( (concat $1 " " $2) )
| LONG
;
builtintype
: signedmod builtintype-types
( (concat (car $1) " " (car $2)) )
| builtintype-types
( ,$1 )
;; Klaus Berndl: unsigned is synonym for unsigned int and signed for
;; signed int. To make this confusing stuff clear we add here the
;; int.
| signedmod
( (concat (car $1) " int") )
;
;; Klaus Berndl: This parses also nonsense like "const volatile int
;; const volatile const const volatile a ..." but IMHO nobody writes
;; such code. Normally we should define a rule like typeformbase-mode
;; which exactly defines the different allowed cases and combinations
;; of declmods (minus the CVDECLMOD) typeformbase and cv-declmods so
;; we could recognize more invalid code but IMHO this is not worth the
;; effort...
codeblock-var-or-fun
: declmods typeformbase declmods
opt-ref var-or-func-decl
( ,(semantic-c-reconstitute-token ,$5 $1 $2 ) )
;
var-or-fun
: codeblock-var-or-fun
( ,$1 )
;; it is possible for a function to not have a type, and
;; it is then assumed to be an int. How annoying.
;; In C++, this could be a constructor or a destructor.
;; Even more annoying. Only ever do this for regular
;; top-level items. Ignore this problem in code blocks
;; so that we don't have to deal with regular code
;; being erroneously converted into types.
| declmods var-or-func-decl
( ,(semantic-c-reconstitute-token ,$2 $1 nil ) )
;
var-or-func-decl
: func-decl
( ,$1 )
| var-decl
( ,$1 )
;
func-decl
: opt-stars opt-class opt-destructor functionname
opt-template-specifier
opt-under-p
arg-list
opt-post-fcn-modifiers
opt-throw
opt-initializers
fun-or-proto-end
( ,$4 'function
;; Extra stuff goes in here.
;; Continue with the stuff we found in
;; this definition
$2 $3 $7 $9 $8 ,$1 ,$11 $5 ,$10)
| opt-stars opt-class opt-destructor functionname
opt-template-specifier
opt-under-p
;; arg-list - - ini this case, a try implies a fcn.
opt-post-fcn-modifiers
opt-throw
opt-initializers
fun-try-end
( ,$4 'function
;; Extra stuff goes in here.
;; Continue with the stuff we found in
;; this definition
$2 $3 nil $8 $7 ,$1 ,$10 $5 ,$9)
;
var-decl
: varnamelist SEMICOLON
( $1 'variable )
;
opt-under-p
: UNDERP
( nil )
| UNDERUNDERP
( nil )
| ;;EMPTY
;
;; Klaus Berndl: symbol -> namespace-symbol
opt-initializers
: COLON namespace-symbol semantic-list opt-initializers
| COMA namespace-symbol semantic-list opt-initializers
| ;;EMPTY
;
opt-post-fcn-modifiers
: post-fcn-modifiers opt-post-fcn-modifiers
( ,(cons ,(car $1) $2) )
| ;;EMPTY
( nil )
;
post-fcn-modifiers
: REENTRANT
| CONST
;
opt-throw
: THROW semantic-list
( EXPAND $2 throw-exception-list )
| ;;EMPTY
;
;; Is this true? I don't actually know.
throw-exception-list
: namespace-symbol COMA throw-exception-list
( ,(cons (car $1) $3) )
| namespace-symbol RPAREN
( ,$1 )
| symbol RPAREN
( $1 )
| LPAREN throw-exception-list
( ,$2 )
| RPAREN
( )
;
opt-bits
: COLON number
( $2 )
| ;;EMPTY
( nil )
;
opt-array
: BRACK_BLCK opt-array
;; Eventually we want to replace the 1 below with a size
;; (if available)
( (cons 1 (car ,$2) ) )
| ;;EMPTY
( nil )
;
opt-assign
: EQUAL expression
( $2 )
| ;;EMPTY
( nil )
;
opt-restrict
: RESTRICT
| ;;EMPTY
;
;; Klaus Berndl: symbol -> namespace-symbol?! I think so. Can be that
;; then also some invalid C++-syntax is parsed but this is better than
;; not parsing valid syntax.
varname
: opt-stars opt-restrict namespace-symbol opt-bits opt-array
( ,$3 ,$1 ,$4 ,$5 )
;
;; I should store more in this def, but leave it simple for now.
;; Klaus Berndl: const and volatile can be written after the type!
variablearg
: declmods typeformbase cv-declmods opt-ref variablearg-opt-name opt-assign
( VARIABLE-TAG (list (append $5 ,$6)) $2 nil
:constant-flag (if (member "const" (append $1 $3)) t nil)
:typemodifiers (delete "const" (append $1 $3))
:reference (car ,$4)
)
;
variablearg-opt-name
: varname
( ,$1 )
| semantic-list arg-list
( (car ( EXPAND $1 function-pointer )) $2)
;; Klaus Berndl: This allows variableargs without an arg-name being
;; parsed correctly even if there several pointers (*)
| opt-stars
( "" ,$1 nil nil nil )
;
varname-opt-initializer
: semantic-list
| opt-assign
| ;; EMPTY
;
varnamelist
: opt-ref varname varname-opt-initializer COMA varnamelist
( ,(cons (append $2 $3) $5) )
| opt-ref varname varname-opt-initializer
( (append $2 $3) )
;
;; Klaus Berndl: Is necessary to parse stuff like
;; class list_of_facts : public list<fact>, public entity
;; and
;; list <shared_ptr<item> >::const_iterator l;
;; Parses also invalid(?) and senseless(?) c++-syntax like
;; symbol<template-spec>::symbol1<template-spec1>::test_iterator
;; but better parsing too much than to less
namespace-symbol
: symbol opt-template-specifier COLON COLON namespace-symbol
( (concat $1 "::" (car $5)) )
| symbol opt-template-specifier
( $1 )
;
;; Don't pull an optional template specifier at the end of the
;; namespace symbol so that it can be picked up by the type.
namespace-symbol-for-typeformbase
: symbol opt-template-specifier COLON COLON namespace-symbol-for-typeformbase
( (concat $1 "::" (car $5)) )
| symbol
( $1 )
;
;; namespace-symbol
;; : symbol COLON COLON namespace-symbol
;; ( (concat $1 "::" (car $4)) )
;; | symbol
;; ( $1 )
;; ;
namespace-opt-class
: symbol COLON COLON namespace-opt-class
( (concat $1 "::" (car $4)) )
;; Klaus Berndl: We must recognize template-specifiers here so we can
;; parse correctly the method-implementations of template-classes
;; outside the template-class-declaration Example:
;; TemplateClass1<T>::method_1(...)
| symbol opt-template-specifier COLON COLON
( $1 )
;
;; Klaus Berndl: The opt-class of a func-decl must be able to
;; recognize opt-classes with namespaces, e.g.
;; Test1::Test2::classname::
opt-class
: namespace-opt-class
( ,$1 )
| ;;EMPTY
( nil )
;
opt-destructor
: TILDE
( t )
| ;;EMPTY
( nil )
;
arg-list
: PAREN_BLCK knr-arguments
( ,$2 )
| PAREN_BLCK
(EXPANDFULL $1 arg-sub-list)
| VOID_BLCK
( )
;
knr-varnamelist
: varname COMA knr-varnamelist
( ,(cons $1 $3) )
| varname
( $1 )
;
knr-one-variable-decl
: declmods typeformbase cv-declmods knr-varnamelist
( VARIABLE-TAG (nreverse $4) $2 nil
:constant-flag (if (member "const" (append $3)) t nil)
:typemodifiers (delete "const" $3)
)
;
knr-arguments
: knr-one-variable-decl SEMICOLON knr-arguments
( ,(append (semantic-expand-c-tag ,$1) ,$3) )
| knr-one-variable-decl SEMICOLON
( ,(semantic-expand-c-tag ,$1) )
;
arg-sub-list
: variablearg
( ,$1 )
| PERIOD PERIOD PERIOD RPAREN
(VARIABLE-TAG "..." "vararg" nil)
| COMA
( nil )
| LPAREN
( nil )
| RPAREN
( nil )
;
operatorsym
: LESS LESS EQUAL
( "<<=" )
| GREATER GREATER EQUAL
( ">>=" )
| LESS LESS
( "<<" )
| GREATER GREATER
( ">>" )
| EQUAL EQUAL
( "==" )
| LESS EQUAL
( "<=" )
| GREATER EQUAL
( ">=" )
| BANG EQUAL
( "!=" )
| PLUS EQUAL
( "+=" )
| MINUS EQUAL
( "-=" )
| STAR EQUAL
( "*=" )
| DIVIDE EQUAL
( "/=" )
| MOD EQUAL
( "%=" )
| AMPERSAND EQUAL
( "&=" )
| OR EQUAL
( "|=" )
| MINUS GREATER STAR
( "->*" )
| MINUS GREATER
( "->" )
| PARENS
( "()" )
| BRACKETS
( "[]" )
| LESS
| GREATER
| STAR
| PLUS PLUS
( "++" )
| PLUS
| MINUS MINUS
( "--" )
| MINUS
| AMPERSAND AMPERSAND
( "&&" )
| AMPERSAND
| OR OR
( "||" )
| OR
| DIVIDE
| EQUAL
| BANG
| TILDE
| MOD
| COMA
;; HAT EQUAL seems to have a really unpleasant result and
;; breaks everything after it. Leave it at the end, though it
;; doesn't seem to work.
| HAT EQUAL
( "^=" )
| HAT
;
functionname
: OPERATOR operatorsym
( ,$2 )
| semantic-list
( EXPAND $1 function-pointer )
| symbol
( $1 )
;
function-pointer
: LPAREN STAR opt-symbol RPAREN
( (concat "*" ,(car $3)) )
| LPAREN symbol RPAREN
( $2 )
;
fun-or-proto-end
: SEMICOLON
( t )
| semantic-list
( nil )
;; Here is an annoying feature of C++ pure virtual methods
| EQUAL ZERO SEMICOLON
( :pure-virtual-flag )
| fun-try-end
( nil )
;
fun-try-end
: TRY opt-initializers BRACE_BLCK fun-try-several-catches
( nil )
;
fun-try-several-catches
: CATCH PAREN_BLCK BRACE_BLCK fun-try-several-catches
( )
| CATCH BRACE_BLCK fun-try-several-catches
( )
| ;; EMPTY
( )
;
type-cast
: semantic-list
( EXPAND $1 type-cast-list )
;
type-cast-list
: open-paren typeformbase close-paren
;
opt-brackets-after-symbol
: brackets-after-symbol
| ;; EMPTY
;
brackets-after-symbol
: PAREN_BLCK
| BRACK_BLCK
;
multi-stage-dereference
: namespace-symbol opt-brackets-after-symbol
PERIOD multi-stage-dereference ;; method call
| namespace-symbol opt-brackets-after-symbol
MINUS GREATER multi-stage-dereference ;;method call
| namespace-symbol opt-brackets-after-symbol
PERIOD namespace-symbol opt-brackets-after-symbol
| namespace-symbol opt-brackets-after-symbol
MINUS GREATER namespace-symbol opt-brackets-after-symbol
| namespace-symbol brackets-after-symbol
;
string-seq
: string string-seq
( (concat $1 (car $2)) )
| string
( $1 )
;
expr-start
: MINUS
| PLUS
| STAR
| AMPERSAND
;
expr-binop
: MINUS
| PLUS
| STAR
| DIVIDE
| AMPERSAND AMPERSAND
| AMPERSAND
| OR OR
| OR
| MOD
;; There are more.
;
;; Use expression for parsing only. Don't actually return anything
;; for now. Hopefully we can fix this later.
expression
: unaryexpression QUESTION unaryexpression COLON unaryexpression
( (identity start) (identity end) )
| unaryexpression expr-binop unaryexpression
( (identity start) (identity end) )
| unaryexpression
( (identity start) (identity end) )
;
unaryexpression
: number
| multi-stage-dereference
| NEW multi-stage-dereference
| NEW builtintype-types semantic-list
| symbol
;; Klaus Berndl: C/C++ allows sequences of strings which are
;; concatenated by the precompiler to one string
| string-seq
| type-cast expression ;; A cast to some other type
;; Casting the results of one expression to something else.
| semantic-list expression
| semantic-list
| expr-start expression
;
;;; c.by ends here