From d71253d7fdb59464e5c094b5b091c87aa2a189d5 Mon Sep 17 00:00:00 2001 From: Adrian Thurston Date: Sun, 1 Dec 2019 09:38:20 -0800 Subject: added C++ and Python grammars, taken from test suite These both need to be updated and tested for code in the wild. They were originally developed to showcase colm features. --- grammar/Makefile | 6 +- grammar/c++/.gitignore | 2 + grammar/c++/Makefile | 7 + grammar/c++/c++.lm | 2248 +++++++++++++++++++++++++++++++++++++++++++++ grammar/c++/expected | 74 ++ grammar/c++/input.cc | 153 +++ grammar/pcre/Makefile | 4 +- grammar/python/.gitignore | 2 + grammar/python/Makefile | 7 + grammar/python/expected | 137 +++ grammar/python/input.py | 47 + grammar/python/python.lm | 579 ++++++++++++ 12 files changed, 3260 insertions(+), 6 deletions(-) create mode 100644 grammar/c++/.gitignore create mode 100644 grammar/c++/Makefile create mode 100644 grammar/c++/c++.lm create mode 100644 grammar/c++/expected create mode 100644 grammar/c++/input.cc create mode 100644 grammar/python/.gitignore create mode 100644 grammar/python/Makefile create mode 100644 grammar/python/expected create mode 100644 grammar/python/input.py create mode 100644 grammar/python/python.lm (limited to 'grammar') diff --git a/grammar/Makefile b/grammar/Makefile index 21a2603a..44ac4032 100644 --- a/grammar/Makefile +++ b/grammar/Makefile @@ -1,6 +1,4 @@ -SUBDIRS = "rust pcre dns" +SUBDIRS = rust pcre dns c++ python all: rust pcre dns - for d in $(SUBDIRS); do cd $$d && $(MAKE); done - - + for d in $(SUBDIRS); do ( cd $$d && $(MAKE) ); done diff --git a/grammar/c++/.gitignore b/grammar/c++/.gitignore new file mode 100644 index 00000000..3c976527 --- /dev/null +++ b/grammar/c++/.gitignore @@ -0,0 +1,2 @@ +/c++.c +/c++ diff --git a/grammar/c++/Makefile b/grammar/c++/Makefile new file mode 100644 index 00000000..e7bfe8d5 --- /dev/null +++ b/grammar/c++/Makefile @@ -0,0 +1,7 @@ +COLM = ../../colm/colm +RAGEL = ../../ragel/ragel + +all: c++ + +c++: c++.lm + $(COLM) -o $@ $< diff --git a/grammar/c++/c++.lm b/grammar/c++/c++.lm new file mode 100644 index 00000000..6aa0a5c5 --- /dev/null +++ b/grammar/c++/c++.lm @@ -0,0 +1,2248 @@ + +context lookup + alias list_lang_object + list + + alias list_declaration_data + list + + alias list_declarator_data + list + + alias list_int + list + + alias map_list_lang_object + map + + # + # Data types for global data. + # + + # Language objects. + struct lang_object + typeId: int + name: str + + # If the object is a typedef, this points to the real object. + typedefOf: lang_object + + objectMap: map_list_lang_object + inherited: list_lang_object + lookupParent: lang_object + specializationOf: lang_object + end + + # This structure is used to keep track of information necessary to make a + # declaration. While parsing a declaration it records the declaration's + # attributes. + struct declaration_data + isTypedef: int + isFriend: int + isTemplate: int + + typeObj: lang_object + end + + struct declarator_data + qualObj: lang_object + pdcScope: lang_object + lookupObj: lang_object + end + + # Constants for language object types. + NamespaceType: int + ClassType: int + TemplateClassType: int + EnumType: int + IdType: int + TypedefType: int + TemplateIdType: int + + # + # Global data declarations + # + + # Object stacks. + curNamespace: list_lang_object + declNs: list_lang_object + lookupNs: list_lang_object + qualNs: list_lang_object + templateParamNs: list_lang_object + + # Declaration, declarator data. + declarationData: list_declaration_data + declaratorData: list_declarator_data + + # Template declarations + templDecl: list_int + + # Root namespace object + rootNamespace: lang_object + + # + # Identifier lookup. + # + + # Lookup the token in the members of an object. + lang_object lookupInObject( obj: lang_object, name: str ) + { + # LOG print( ' looking in ', obj->name, '\n' ) + + ol: list_lang_object = obj->objectMap->find( name ) + if ol { + # LOG print( ' * found an object: ', ol.head, '\n' ) + return ol->head + } + + return nil + } + + # Lookup in an object and all the objects beneath it in the inheritance + # tree. + lang_object lookupWithInheritance( obj: lang_object, name: str ) + { + found: lang_object = lookupInObject( obj, name ) + if found + return found + + for inh: lang_object in obj->inherited { + # First check if the inherited object is the one we are after. + if inh->name == name && inh->typeId == ClassType { + # LOG print( ' * found a class name\n' ) + return inh + } + + # Otherwise look inside the inherited object. + found = lookupWithInheritance( inh, name ) + if found + return found + } + + return nil + } + + lang_object unqualifiedLookup( name: str ) + { + found: lang_object + + # Start with the objects in the templateParamNs. + for Obj: lang_object in rev_list_iter( templateParamNs ) { + found = lookupWithInheritance( Obj, name ) + if found + break + } + + if !found { + # Iterator over the objects starting at the head of the lookup stack + # and going up through the lookup parents. + lookupIn: lang_object = lookupNs->tail + while lookupIn { + found = lookupWithInheritance( lookupIn, name ) + if found + break + lookupIn = lookupIn->lookupParent + } + } + + return found + } + + # The C++ scanner. + lex + rl fract_const / digit* '.' digit+ | digit+ '.' / + rl exponent / [eE] [+\-]? digit+ / + rl float_suffix / [flFL] / + + # Single and double literals. + token TK_SingleLit /( 'L'? "'" ( [^'\\\n] | '\\' any )* "'" )/ + token TK_DoubleLit /( 'L'? '"' ( [^"\\\n] | '\\' any )* '"' )/ + + literal `extern `namespace `friend `typedef `auto `register + `static `mutable `inline `virtual `explicit `const + `volatile `restrict `class `struct `union `template + `private `protected `public `using `void `char + `wchar_t `bool `int `float `double `short `long + `signed `unsigned `enum `new `delete `operator + `typename `export `throw `try `catch `sizeof + `dynamic_cast `static_cast `reinterpret_cast `const_cast + `typeid `this `true `false `switch `case `default + `if `else `while `do `for `break `continue + `return `goto + + # Extensions + literal `__typeof `__is_pod `__is_empty + + literal `{ `} `; `, `= `( `) `: `& `* `[ `] `~ `+ `- + `/ `< `> `| `^ `% `! `? `. + + literal `:: `== `!= `&& `|| `*= `/= `%= `+= `-= `&= + `^= `|= `++ `-- `-> `->* `.* `... `<<= `>>= + + # Token translation targets. + def unknown_id [lookup_id] + def class_id [lookup_id] + def namespace_id [lookup_id] + def templ_class_id [lookup_id] + def enum_id [lookup_id] + def typedef_id [lookup_id] + def identifier [lookup_id] + def template_id [lookup_id] + + # Identifiers + token lookup_id + obj: lang_object + qualObj: lang_object + + /( [a-zA-Z_] [a-zA-Z0-9_]* )/ + { + name: str = match_text + found: lang_object = nil + qualObj: lang_object = nil + if qualNs->tail { + # LOG print( 'qualified lookup of ', name, '\n' ) + + # Transfer the qualification to the token and reset it. + qualObj = qualNs->tail + qualNs->pop_tail() + qualNs->push_tail( nil ) + + # Lookup using the qualification. + found = lookupWithInheritance( qualObj, name ) + } + else { + # No qualification, full search. + # LOG print( 'unqualified lookup of ', name, '\n' ) + found = unqualifiedLookup( name ) + } + + # If no match, return an Unknown ID + id: int = typeid + if found + id = found->typeId + + LookupId: lookup_id = make_token( typeid, + input->pull(match_length) ) + LookupId.obj = found + LookupId.qualObj = qualObj + + input->push( make_tree( id, LookupId ) ) + } + + # Floats. + token TK_Float /( fract_const exponent? float_suffix? | + digit+ exponent float_suffix? )/ + + # Integer decimal. Leading part buffered by float. + token TK_IntegerDecimal /( ( '0' | [1-9] [0-9]* ) [ulUL]{0,3} )/ + + # Integer octal. Leading part buffered by float. + token TK_IntegerOctal /( '0' [0-9]+ [ulUL]{0,2} )/ + + # Integer hex. Leading 0 buffered by float. + token TK_IntegerHex /( '0x' [0-9a-fA-F]+ [ulUL]{0,2} )/ + + # Preprocessor line. + ignore /'#' [^\n]* '\n'/ + + # Comments and whitespace. + ignore /( '/*' (any | '\n')* :>> '*/' )/ + ignore /( '//' any* :> '\n' )/ + ignore /( any - 33..126 )+/ + end + + # + # Support functions + # + + typeId: int + name: str + + # If the object is a typedef, this points to the real object. + typedefOf: lang_object + + objectMap: map_list_lang_object + inherited: list_lang_object + lookupParent: lang_object + specializationOf: lang_object + + lang_object createLangObject( typeId: int, name: str, lookupParent: lang_object ) + { + Obj: lang_object = new lang_object() + + Obj->typeId = typeId + Obj->name = name + Obj->typedefOf = nil + Obj->objectMap = new map_list_lang_object() + Obj->inherited = new list_lang_object() + Obj->lookupParent = lookupParent + + return Obj + } + + # Building the language object tree. + int insertObject( definedIn: lang_object, name: str, obj: lang_object ) + { + ol: list_lang_object = definedIn->objectMap->find( name ) + if !ol { + # Element not in the map already + ol = new list_lang_object() + definedIn->objectMap->insert( name, ol ) + } + ol->push_tail( obj ) + } + + lang_object findClass( inObj: lang_object, lang_objectname: str ) + { + List: list_lang_object = inObj->objectMap->find( name ) + if List { + for obj: lang_object in List { + if obj->typeId == ClassType { + return obj + } + } + } + return nil + } + + lang_object findTemplateClass( inObj: lang_object, name: str ) + { + List: list_lang_object = inObj->objectMap->find( name ) + if List { + for obj: lang_object in List { + if obj->typeId == TemplateClassType + return obj + } + } + return nil + } + + def root_qual_opt + [] + | [`::] + + def nested_name_specifier_opt + [nested_name_specifier_opt qualifying_name `:: designated_qualifying_name `::] + | [nested_name_specifier_opt qualifying_name `::] + | [] + + def nested_name_specifier + [nested_name_specifier designated_qualifying_name `::] + | [nested_name_specifier qualifying_name `::] + | [qualifying_name `::] + + def qualifying_name + [class_name] + { + qualNs->pop_tail() + qualNs->push_tail( r1.lookupId.obj ) + } + + | [namespace_id] + { + match r1 [Id: lookup_id] + qualNs->pop_tail() + qualNs->push_tail( Id.obj ) + } + + | [typedef_id] + { + match r1 [Id: lookup_id] + qualNs->pop_tail() + qualNs->push_tail( Id.obj->typedefOf ) + } + + def designated_qualifying_name + [`template any_id] + { + # FIXME: nulling qualNs is not the right thing to do here. + qualNs->pop_tail() + qualNs->push_tail( nil ) + } + + | [`template any_id + templ_arg_open template_argument_list_opt templ_arg_close] + { + # FIXME: nulling qualNs is not the right thing to do here. + qualNs->pop_tail() + qualNs->push_tail( nil ) + } + + # + # Id Expression + # + + def id_expression + lookupId: lookup_id + + [root_qual_opt nested_name_specifier_opt unknown_id] + { + lhs.lookupId = lookup_id in r3 + } + + | [root_qual_opt nested_name_specifier_opt identifier] + { + lhs.lookupId = lookup_id in r3 + } + + | [root_qual_opt nested_name_specifier_opt operator_function_id] + { + # Normally the token translation transfers the qualification. Since + # the operator_function_id does not end in a lookup we must do it ourselves. + qualObj: lang_object = qualNs->pop_tail() + qualNs->push_tail( nil ) + + lhs.lookupId = construct lookup_id ["x"] + lhs.lookupId.data = '' + lhs.lookupId.qualObj = qualObj + } + + | [root_qual_opt nested_name_specifier_opt conversion_function_id] + { + # Normally the token translation transfers the qualification. Since + # the operator_function_id does not } in a lookup we must do it ourselves. + qualObj: lang_object = qualNs->pop_tail() + qualNs->push_tail( nil ) + + # Do we need qual reset here becauase operator_function_id does not do it? + lhs.lookupId = construct lookup_id ["x"] + lhs.lookupId.data = '' + lhs.lookupId.qualObj = qualObj + } + + | [root_qual_opt nested_name_specifier_opt `~ class_name] + { + lhs.lookupId = r4.lookupId + } + + | [root_qual_opt nested_name_specifier_opt template_name] + { + lhs.lookupId = r3.lookupId + } + + def template_name + lookupId: lookup_id + + [template_id templ_arg_open template_argument_list_opt templ_arg_close] + { + lhs.lookupId = lookup_id in r1 + } + + | [template_id] + { + lhs.lookupId = lookup_id in r1 + } + + + # + # Class Names + # + + def class_name + lookupId: lookup_id + + [class_id] + { + lhs.lookupId = lookup_id in r1 + } + + | [templ_class_id] + { + lhs.lookupId = lookup_id in r1 + } + + | [templ_class_id templ_arg_open template_argument_list_opt templ_arg_close] + { + # TODO: Look for a specialization. + lhs.lookupId = lookup_id in r1 + } + + def templ_arg_open + [`<] + { + qualNs->push_tail( nil ) + } + + def templ_arg_close + [`>] + { + qualNs->pop_tail() + } + + def declaration + [block_declaration] commit + | [function_definition] commit + | [template_declaration] commit + | [explicit_instantiation] commit + | [explicit_specialization] commit + | [linkage_specification] commit + | [namespace_definition] commit + + # + # Declarations + # + + def block_declaration + [simple_declaration] + | [using_declaration] + | [using_directive] + + def simple_declaration + [declaration_start simple_declaration_forms declaration_end `;] + + # Ordering is important for optimization. The form with the optional + # decl_specifier_sing should go second. + def simple_declaration_forms + [decl_specifier_mult_seq_opt decl_specifier_sing + decl_specifier_mult_seq_opt init_declarator_list_opt] + + | [decl_specifier_mult_seq_opt init_declarator_list_opt] + + def declaration_start + [] + { + # LOG print( 'opening new declaration_data with templDecl: ', templDecl.tail, '\n' ) + DD: declaration_data = new declaration_data() + DD->isTypedef = 0 + DD->isFriend = 0 + DD->isTemplate = 0 + declarationData->push_tail( DD ) + + # Transfer the template flag and reset it. + declarationData->tail->isTemplate = templDecl->tail + templDecl->push_tail( 0 ) + } + + def declaration_end + [] + { + # LOG print( 'closing declaration_data\n' ) + declarationData->pop_tail() + templDecl->pop_tail() + } + + def decl_specifier_sing + [type_specifier_sing] + { + # Store the object type of the declaration (if any) for use + # by typedefs. + declarationData->tail->typeObj = r1.lookupId.obj + } + + def type_specifier_seq + lookupId: lookup_id + + [type_specifier_mult_seq_opt type_specifier_sing type_specifier_mult_seq_opt] + { + lhs.lookupId = r2.lookupId + } + + def type_specifier_sing + lookupId: lookup_id + + [simple_type_specifier] + { + lhs.lookupId = r1.lookupId + } + + | [class_specifier] + { + lhs.lookupId = construct lookup_id ["x"] + lhs.lookupId.data = '' + } + + | [enum_specifier] + { + lhs.lookupId = construct lookup_id ["x"] + lhs.lookupId.data = '' + } + + | [elaborated_type_specifier] + { + lhs.lookupId = construct lookup_id ["x"] + lhs.lookupId.data = '' + } + + # Type specifier sequence without enum specifier or class specifier. + def necs_type_specifier_seq + [type_specifier_mult_seq_opt necs_type_specifier_sing type_specifier_mult_seq_opt] + + # Type specifier singular without enum specifier or class specifier. + def necs_type_specifier_sing + [simple_type_specifier] + | [elaborated_type_specifier] + + def type_specifier_mult_seq_opt + [type_specifier_mult_seq_opt type_specifier_mult] + | [] + + def type_specifier_mult_seq + [type_specifier_mult_seq type_specifier_mult] + | [type_specifier_mult] + + def simple_type_specifier + lookupId: lookup_id + + [simple_type_specifier_name] + { + lhs.lookupId = r1.lookupId + } + + | [simple_type_specifier_kw_seq] + { + lhs.lookupId = construct lookup_id ["x"] + lhs.lookupId.data = '' + } + + | [`typename root_qual_opt nested_name_specifier type_name] + { + lhs.lookupId = r4.lookupId + } + + | [`typename root_qual_opt nested_name_specifier identifier] + { + lhs.lookupId = lookup_id in r4 + } + + | [`typename root_qual_opt nested_name_specifier unknown_id] + { + lhs.lookupId = lookup_id in r4 + } + + # Extension. + | [`__typeof `( expression `)] + { + lhs.lookupId = construct lookup_id ["x"] + lhs.lookupId.data = '' + } + + def simple_type_specifier_name + lookupId: lookup_id + + [qual_type_name] + { + lhs.lookupId = r1.lookupId + } + + def simple_type_specifier_kw_seq + [simple_type_specifier_kw_seq simple_type_specifier_kw] + | [simple_type_specifier_kw] + + def simple_type_specifier_kw + [`void] + | [`char] + | [`wchar_t] + | [`bool] + | [`int] + | [`float] + | [`double] + | [`short] + | [`long] + | [`signed] + | [`unsigned] + + def qual_type_name + lookupId: lookup_id + + [root_qual_opt nested_name_specifier_opt type_name] + { + lhs.lookupId = r3.lookupId + } + + def type_name + lookupId: lookup_id + + [class_name] + { + lhs.lookupId = r1.lookupId + } + + | [enum_id] + { + lhs.lookupId = lookup_id in r1 + } + + | [typedef_id] + { + lhs.lookupId = lookup_id in r1 + } + + # NOTE: the typename case is moved to simple type specifier + # to take advantage of its conflict resolution. + def elaborated_type_specifier + [class_key nested_name_specifier_opt class_head_name] + { + Id: lookup_id = lookup_id in r3 + name: str = Id.data + + # Get the ns the class is declared in. + parentObj: lang_object = declNs->tail + if Id.qualObj + parentObj = Id.qualObj + + # Look for the class in the given scope. + declaredClass: lang_object = findClass( parentObj, name ) + if !declaredClass + declaredClass = findTemplateClass( parentObj, name ) + + if !declaredClass { + # LOG print( 'creating new class: ', name, '\n' ) + + # Class does not exist in the parent scope, create it. + nsType: int = declaredClassType() + + declaredClass = createLangObject( nsType, name, lookupNs->tail ) + + # FIXME: handle friends. Make the class visible only if we are NOT + # in a friend declaration. The new class object is necessary to + # properly process the body of the class. + if declarationData->tail->isFriend == 0 + insertObject( parentObj, name, declaredClass ) + } + } + + # TODO: Lookup type specialization. + | [class_key nested_name_specifier_opt templ_class_id + templ_arg_open template_argument_list_opt templ_arg_close] + + | [`enum nested_name_specifier_opt enum_head_name] + { + # TODO: should look for existing enums of the same name. + Id: lookup_id = lookup_id in r3 + # LOG print( 'creating enumeration ' Id.data '\n' ) + enum: lang_object = createLangObject( EnumType, Id.data, lookupNs->tail ) + insertObject( declNs->tail, Id.data, enum ) + } + + def decl_specifier_mult_seq_opt + [decl_specifier_mult_seq_opt decl_specifier_mult] + | [] + + def decl_specifier_mult_seq + [decl_specifier_mult_seq decl_specifier_mult] + | [decl_specifier_mult] + + def decl_specifier_mult + [type_specifier_mult] + | [storage_class_specifier] + | [function_specifier] + + | [`friend] + { + declarationData->tail->isFriend = 1 + } + + | [`typedef] + { + declarationData->tail->isTypedef = 1 + } + + def storage_class_specifier + [`auto] + | [`register] + | [`static] + | [`extern] + | [`mutable] + + def function_specifier + [`inline] + | [`virtual] + | [`explicit] + + def type_specifier_mult + [cv_qualifier] + + def cv_qualifier + [`const] + | [`volatile] + | [`restrict] + + def cv_qualifier_rep + [cv_qualifier_rep cv_qualifier] + | [] + + def namespace_definition + [named_namespace_definition] + | [unnamed_namespace_definition] + + def named_namespace_definition + [original_namespace_definition] + | [extension_namespace_definition] + + # + # Enumerations + # + + def enum_specifier + [`enum nested_name_specifier_opt + enum_head_name `{ enumerator_list_opt `}] + { + # TODO: should look for existing enums of the same name. + Id: lookup_id = lookup_id in r3 + # LOG print( 'creating enumeration ' Id.data '\n' ) + enum: lang_object = createLangObject( EnumType, Id.data, lookupNs->tail ) + insertObject( declNs->tail, Id.data, enum ) + } + + | [`enum `{ enumerator_list_opt `}] + + def enum_head_name + [class_id] + | [templ_class_id] + | [namespace_id] + | [typedef_id] + | [enum_id] + | [identifier] + | [template_id] + | [unknown_id] + + def enumerator_list_opt + [enumerator_list] + | [enumerator_list `,] + | [] + + def enumerator_list + [enumerator_list `, enumerator_definition] + | [enumerator_definition] + + def enumerator_definition + [enumerator_id] + { + Id: lookup_id = lookup_id in r1 + enumId: lang_object = createLangObject( IdType, Id.data, lookupNs->tail ) + insertObject( declNs->tail, Id.data, enumId ) + } + + | [enumerator_id `= constant_expression] + { + Id: lookup_id = lookup_id in r1 + enumId: lang_object = createLangObject( IdType, Id.data, lookupNs->tail ) + insertObject( declNs->tail, Id.data, enumId ) + } + + def enumerator_id + [namespace_id] + | [typedef_id] + | [enum_id] + | [class_id] + | [templ_class_id] + | [template_id] + | [identifier] + | [unknown_id] + + # + # Declarators + # + + def init_declarator_list_opt + [init_declarator_list] + | [] + + def init_declarator_list + [init_declarator_list `, init_declarator] + | [init_declarator] + + def init_declarator + [declarator initializer_opt] + + def initializer_opt + [`= initializer_clause] + | [`( expression `)] + | [] + + def initializer_clause + [assignment_expression] + | [`{ initializer_list `}] + | [`{ initializer_list `, `}] + | [`{ `}] + + def initializer_list + [initializer_list `, initializer_clause] + | [initializer_clause] + + # + # Expressions + # + + def expression + [expression `, assignment_expression] + | [assignment_expression] + + def expression_opt + [expression] + | [] + + def constant_expression + [conditional_expression] + + def constant_expression_opt + [constant_expression] + | [] + + def assignment_expression + [conditional_expression] + | [logical_or_expression assignment_op assignment_expression] + | [throw_expression] + + def assignment_op + [`=] + | [`*=] + | [`/=] + | [`%=] + | [`+=] + | [`-=] + | [`>>=] + | [`<<=] + | [`&=] + | [`^=] + | [`|=] + + def conditional_expression + [logical_or_expression] + | [logical_or_expression `? expression `: assignment_expression] + + def logical_or_expression + [logical_or_expression `|| logical_and_expression] + | [logical_and_expression] + + def logical_and_expression + [logical_and_expression `&& inclusive_or_expression] + | [inclusive_or_expression] + + def inclusive_or_expression + [inclusive_or_expression `| exclusive_or_expression] + | [exclusive_or_expression] + + def exclusive_or_expression + [exclusive_or_expression `^ and_expression] + | [and_expression] + + def and_expression + [and_expression `& equality_expression] + | [equality_expression] + + def equality_expression + [equality_expression `== relational_expression] + | [equality_expression `!= relational_expression] + | [relational_expression] + + def relational_expression + [relational_expression `< shift_expression] + | [relational_expression `> shift_expression] + | [relational_expression lt_eq shift_expression] + | [relational_expression gt_eq shift_expression] + | [shift_expression] + + def shift_expression + [shift_expression shift_left additive_expression] + | [shift_expression shift_right additive_expression] + | [additive_expression] + + def additive_expression + [additive_expression `+ multiplicative_expression] + | [additive_expression `- multiplicative_expression] + | [multiplicative_expression] + + def multiplicative_expression + [multiplicative_expression `* pm_expression] + | [multiplicative_expression `/ pm_expression] + | [multiplicative_expression `% pm_expression] + | [pm_expression] + + def pm_expression + [pm_expression `->* cast_expression] + | [pm_expression `.* cast_expression] + | [cast_expression] + + def cast_expression + [unary_expression] + | [`( type_id `) cast_expression] + + def delete_expression + [root_qual_opt `delete cast_expression] + | [root_qual_opt `delete `[ `] cast_expression] + + def new_initializer_opt + [new_initializer] + | [] + + def new_initializer + [`( expression_opt `)] + + def direct_new_declarator + [`[ expression `]] + | [direct_new_declarator `[ constant_expression `]] + + def new_declarator_opt + [new_declarator] + | [] + + def new_declarator + [direct_new_declarator] + | [ptr_operator_seq direct_new_declarator] + | [ptr_operator_seq] + + def new_type_id + [necs_type_specifier_seq new_declarator_opt] + + def new_placement + [`( expression `)] + + def new_expression + [root_qual_opt `new new_type_id new_initializer_opt] + | [root_qual_opt `new new_placement new_type_id new_initializer_opt] + | [root_qual_opt `new `( type_id `) new_initializer_opt] + | [root_qual_opt `new new_placement `( type_id `) new_initializer_opt] + + def unary_operator + [`*] + | [`&] + | [`+] + | [`-] + | [`!] + | [`~] + + def unary_expression + [postfix_expression] + | [`++ cast_expression] + | [`-- cast_expression] + | [unary_operator cast_expression] + | [`sizeof `( type_id `)] + | [`sizeof unary_expression] + | [new_expression] + | [delete_expression] + + def function_style_type_conv + [simple_type_specifier] + + + def postfix_expression + [primary_expression] + | [postfix_expression `[ expression `]] + | [postfix_expression `( expression_opt `)] + | [function_style_type_conv `( expression_opt `)] + | [member_request_expr dot_arrow id_expression] + | [member_request_expr dot_arrow pseudo_destructor_call] + | [postfix_expression `++] + | [postfix_expression `--] + | [`dynamic_cast templ_arg_open type_id templ_arg_close `( expression `)] + | [`static_cast templ_arg_open type_id templ_arg_close `( expression `)] + | [`reinterpret_cast templ_arg_open type_id templ_arg_close `( expression `)] + | [`const_cast templ_arg_open type_id templ_arg_close `( expression `)] + | [`typeid `( expression `)] + | [`typeid `( type_id `)] + + def pseudo_destructor_call + [root_qual_opt nested_name_specifier_opt `~ pdc_type_name] + + def primary_expression + [expr_lit] + | [`this] + | [`( expression `)] + | [id_expression] + # GNU extensions + | [`( `{ statement_rep `} `)] + | [`__is_pod `( type_id `)] + | [`__is_empty `( type_id `)] + + def expr_lit + [TK_IntegerDecimal] + | [TK_IntegerOctal] + | [TK_IntegerHex] + | [TK_SingleLit] + | [TK_Float] + | [double_lit_list] + | [`true] + | [`false] + + def double_lit_list + [TK_DoubleLit double_lit_list] + | [TK_DoubleLit] + + def member_request_expr + [postfix_expression] + # { + # # FIXME: If no proper type is found, we must fail. + # # LOG print( 'setting member request scope\n' ) + # # qualNs.set( $1->type != 0 ? $1->type->getObject() : 0 ); + # } + + def dot_arrow + [`->] + | [`.] + + def pdc_type_name + [enum_id] + | [typedef_id] + + # + # Statements + # + + def statement_rep + [statement_rep statement] + | [] + + def statement + [declaration_statement] + | [labeled_statement] + | [expression_statement] + | [compound_statement] + | [selection_statement] + | [iteration_statement] + | [jump_statement] + | [try_block] + + def labeled_statement + [label_id `: statement] + | [`case constant_expression `: statement] + | [`default `: statement] + + def label_id + [unknown_id] + | [identifier] + | [class_id] + | [templ_class_id] + | [namespace_id] + | [typedef_id] + | [enum_id] + | [template_id] + + def compound_statement + [`{ compound_begin statement_rep compound_end `}] + + def compound_begin + [] + { + newCompound: lang_object = createLangObject( 0, + '', lookupNs->tail ) + lookupNs->push_tail( newCompound ) + + declNs->push_tail( newCompound ) + # LOG print( 'opening \n' ) + } + + def compound_end + [] + { + lookupNs->pop_tail() + declNs->pop_tail() + # LOG print( 'closing \n' ) + } + + def selection_statement + [`if `( condition `) statement elseif_clauses else_clause] + | [`switch `( condition `) statement] + + def elseif_clauses + [elseif_clauses `else `if `( condition `) statement] + | [] + + def else_clause + [`else statement] + | [] + + def iteration_statement + [`while `( condition `) statement] + | [`do statement `while `( expression `) `;] + | [`for `( for_init_statement condition_opt `; expression_opt `) statement] + + def jump_statement + [`break `;] + | [`continue `;] + | [`return expression_opt `;] + | [`goto any_id `;] + + def any_id + [unknown_id] + | [class_id] + | [namespace_id] + | [templ_class_id] + | [enum_id] + | [typedef_id] + | [identifier] + | [template_id] + + + def for_init_statement + [expression_statement] + | [stmt_block_declaration_forms `;] + + def condition + [expression] + | [type_specifier_seq declarator `= assignment_expression] + + def condition_opt + [condition] + | [] + + def expression_statement + [expression `;] + | [`;] + + def declaration_statement + [stmt_block_declaration] + + def stmt_block_declaration + [declaration_start stmt_block_declaration_forms declaration_end `;] + | [using_declaration] + | [using_directive] + + def stmt_block_declaration_forms + [decl_specifier_mult_seq_opt decl_specifier_sing decl_specifier_mult_seq_opt + init_declarator_list_opt] + | [decl_specifier_mult_seq init_declarator_list_opt] + + # + # Declarators + # + + def declarator + lookupObj: lang_object + + [ptr_operator_seq_opt declarator_id decl_array_or_param_rep declarator_end] + { + lhs.lookupObj = r4.lookupObj + } + + | [ptr_operator_seq_opt `( sub_declarator `) decl_array_or_param_rep declarator_end] + { + lhs.lookupObj = r6.lookupObj + } + + def sub_declarator + [ptr_operator_seq declarator_id decl_array_or_param_rep] + | [ptr_operator_seq `( sub_declarator `) decl_array_or_param_rep] + | [`( sub_declarator `) decl_array_or_param_rep] + | [declarator_id decl_array_or_param_rep] + + def decl_array_or_param_rep + [decl_array_or_param_rep decl_array_or_param] + | [] + + def decl_array_or_param + [`[ constant_expression_opt `]] + | [`( parameter_declaration_clause `) cv_qualifier_rep exception_specification_opt] + + def declarator_id + [declarator_id_forms] + { + name: str = r1.lookupId.data + qualObj: lang_object = r1.lookupId.qualObj + + parentObj: lang_object = declNs->tail + if qualObj + parentObj = qualObj + + # Decide if we are declaring a constructor/destructor. + isConstructor: bool + if parentObj == r1.lookupId.obj { + isConstructor = true + # LOG print( 'making declarator ' name ' a constructor/destructor\n' ) + } + + if parentObj->specializationOf && + parentObj->specializationOf == r1.lookupId.obj + { + isConstructor = true + # LOG print( 'making declarator ' name ' a constructor/destructor\n' ) + } + + obj: lang_object = nil + if name && !isConstructor && declarationData->tail->isFriend == 0 { + if declarationData->tail->isTypedef { + obj = createLangObject( TypedefType, name, lookupNs->tail ) + obj->typedefOf = declarationData->tail->typeObj + insertObject( parentObj, name, obj ) + + # LOG print( 'making declarator ' name ' a typedef\n' ) + } + else { + if !qualObj { + if declarationData->tail->isTemplate { + # If in a template declaration and the name is not qualified then + # create the template id. + obj = createLangObject( TemplateIdType, name, lookupNs->tail ) + #object->objType = declarationData.tail.type + insertObject( declNs->tail, name, obj ) + + # LOG print( 'making declarator ' name ' a template id\n' ) + } + else { + obj = createLangObject( IdType, name, lookupNs->tail ) + #object->objType = declarationData.tail().type; + insertObject( declNs->tail, name, obj ) + + # LOG print( 'making declarator ' name ' an id\n' ) + } + } + } + } + + + DD: declarator_data = new declarator_data() + DD->qualObj = qualObj + DD->pdcScope = nil + DD->lookupObj = lookupNs->tail + + declaratorData->push_tail( DD ) + + # If the declarator is qualified, push the qualification to the lookup + # stack. Also save it in the declarator data so it can be passed to a + # function body if needed. + if qualObj { + lookupNs->push_tail( qualObj ) + declaratorData->tail->lookupObj = qualObj + } + + # LOG print( 'reduced declarator_id: ' name '\n' ) + } + + # Undoes the setup done by declarator_id and pdc_start. + def declarator_end + lookupObj: lang_object + + [] + { + # Get the lookupObject from the scope and pass it up. If we are about to + # parse a function body it will be needed. + lhs.lookupObj = declaratorData->tail->lookupObj + + pdcScope: lang_object = declaratorData->tail->pdcScope + qualObj: lang_object = declaratorData->tail->qualObj + + declaratorData->pop_tail() + + if pdcScope { + # LOG print( 'closing \n' ) + lookupNs->pop_tail() + declNs->pop_tail() + } + + if qualObj { + # LOG print( 'popping lookupNs\n' ) + lookupNs->pop_tail() + } + } + + def declarator_id_forms + lookupId: lookup_id + + [id_expression] + { + lhs.lookupId = r1.lookupId + } + + | [root_qual_opt nested_name_specifier_opt type_name] + { + lhs.lookupId = r3.lookupId + } + + | [root_qual_opt nested_name_specifier_opt `~ class_id] + { + lhs.lookupId = lookup_id in r4 + } + + | [root_qual_opt nested_name_specifier_opt `~ templ_class_id] + { + lhs.lookupId = lookup_id in r4 + } + | [root_qual_opt nested_name_specifier_opt `~ unknown_id] + { + lhs.lookupId = lookup_id in r4 + } + + def type_id + lookupId: lookup_id + + [type_specifier_seq abstract_declarator_opt] + { + lhs.lookupId = r1.lookupId + } + + def abstract_declarator_opt + [abstract_declarator] + | [] + + def abstract_declarator + [ptr_operator_seq abstract_noid abstract_decl_array_or_param_seq_opt declarator_end] + | [ptr_operator_seq `( sub_abstract_declarator `) + abstract_decl_array_or_param_seq_opt declarator_end] + | [abstract_noid abstract_decl_array_or_param_seq declarator_end] + | [`( sub_abstract_declarator `) abstract_decl_array_or_param_seq_opt declarator_end] + + def sub_abstract_declarator + [ptr_operator_seq abstract_noid abstract_decl_array_or_param_seq_opt] + + | [ptr_operator_seq `( sub_abstract_declarator `) + abstract_decl_array_or_param_seq_opt] + + | [`( sub_abstract_declarator `) abstract_decl_array_or_param_seq_opt] + + def abstract_noid + [] + { + # Make scope for declarator. + DD: declarator_data = new declarator_data() + declaratorData->push_tail( DD ) + } + + def abstract_decl_array_or_param_seq_opt + [abstract_decl_array_or_param_seq_opt abstract_decl_array_or_param] + | [] + + def abstract_decl_array_or_param_seq + [abstract_decl_array_or_param_seq abstract_decl_array_or_param] + | [abstract_decl_array_or_param] + + def abstract_decl_array_or_param + [`[ constant_expression_opt `]] + | [`( parameter_declaration_clause `) cv_qualifier_rep + exception_specification_opt] + + def parameter_declaration_clause + [pdc_start parameter_declaration_list] + | [pdc_start parameter_declaration_list `...] + | [pdc_start parameter_declaration_list `, `...] + | [pdc_start `...] + | [pdc_start] + + def pdc_start + [] + { + if !declaratorData->tail->pdcScope { + # We are going to need a scope for the declarator. + pdcScope: lang_object = createLangObject( 0, + '', lookupNs->tail ) + + lookupNs->push_tail( pdcScope ) + declNs->push_tail( pdcScope ) + + declaratorData->tail->pdcScope = pdcScope + declaratorData->tail->lookupObj = pdcScope + # LOG print( 'opening \n' ) + } + } + + def parameter_declaration_list + [parameter_declaration_list `, parameter_declaration] + | [parameter_declaration] + + def parameter_declaration + [declaration_start parameter_declaration_forms declaration_end] + + # Ordering the productions such that decl_specifier_sing is tried first is good + # for performance. + def parameter_declaration_forms + [decl_specifier_mult_seq_opt decl_specifier_sing decl_specifier_mult_seq_opt + param_maybe_declarator maybe_parameter_init] + + | [decl_specifier_mult_seq param_maybe_declarator maybe_parameter_init] + + def param_maybe_declarator + [abstract_declarator] + | [declarator] + | [] + + def maybe_parameter_init + [`= constant_expression] + | [] + + def ptr_operator + [`&] + | [root_qual_opt nested_name_specifier_opt `* cv_qualifier_rep] + + def ptr_operator_seq + [ptr_operator_seq ptr_operator] + | [ptr_operator] + + def ptr_operator_seq_opt + [ptr_operator_seq_opt ptr_operator] + | [] + + # + # Functions + # + + def function_definition + [function_def_declaration ctor_initializer_opt function_body function_def_end] + + def function_def_declaration + [declaration_start function_def_declaration_forms declaration_end] + + def function_def_declaration_forms + [decl_specifier_mult_seq_opt decl_specifier_sing + decl_specifier_mult_seq_opt function_def_declarator] + | [decl_specifier_mult_seq function_def_declarator] + | [function_def_declarator] + + def function_def_declarator + [declarator] + { + # The lookupObj from the declarator is the deepest lookup object found + # while parsing the declarator. Make it visible in the function body. + # This could be the args, the qualObj, or the parent to the function. + lookupNs->push_tail( r1.lookupObj ) + } + + def function_def_end + [] + { + # Pop the lookup object. + lookupNs->pop_tail() + } + + def function_body + [function_body_begin `{ statement_rep function_body_end `}] + + def function_body_begin + [] + { + newFunctionBody: lang_object = createLangObject( 0, + '', lookupNs->tail ) + + lookupNs->push_tail( newFunctionBody ) + + declNs->push_tail( newFunctionBody ) + + templDecl->push_tail( 0 ) + # LOG print( 'opening \n' ) + } + + def function_body_end + [] + { + # First undoes the function body begin work. Then undoes the setup in + # function_def_declarator. + declNs->pop_tail() + lookupNs->pop_tail() + templDecl->pop_tail() + # LOG print( 'closing \n' ) + } + + + + # + # Classs + # + + int declaredClassType() + { + if declarationData->tail->isTemplate { + return TemplateClassType + } else { + return ClassType + } + } + + def class_specifier + [class_head base_clause_opt `{ class_member_rep class_body_end `}] + { + # FIXME: reparse not implemented yet + # FIXME FIXME: reparse is actually implemented now implemented + # # Visit class function bodies, but skip nested classes. + # for CFB: class_function_body in lhs { + # skipping class_specifier + # + # # Reparse the text of the class function body as a function body + # function_body FB = parse function_body[ $CFB ] + # + # # Replace the class function body with the parsed function body. + # CFB = cons class_function_body [FB.tree] + # } + } + + def class_head + [class_key] + { + nsType: int = declaredClassType() + + # LOG print( 'creating new anonymous class\n' ) + newClass: lang_object = createLangObject( nsType, + '', lookupNs->tail ) + + lookupNs->push_tail( newClass ) + declNs->push_tail( newClass ) + } + + | [class_key nested_name_specifier_opt class_head_name] + { + Id: lookup_id = lookup_id in r3 + name: str = Id.data + + # Get the ns the class is declared in. + parentObj: lang_object = declNs->tail + if Id.qualObj + parentObj = Id.qualObj + + # Look for the class in the given scope. + declaredClass: lang_object = findClass( parentObj, name ) + if !declaredClass + declaredClass = findTemplateClass( parentObj, name ) + + if !declaredClass { + # LOG print( 'creating new class: ' name '\n' ) + + # Class does not exist in the parent scope, create it. + nsType: int = declaredClassType() + + declaredClass = createLangObject( nsType, name, lookupNs->tail ) + + # FIXME: handle friends. Make the class visible only if we are NOT + # in a friend declaration. The new class object is necessary to + # properly process the body of the class. + if declarationData->tail->isFriend == 0 + insertObject( parentObj, name, declaredClass ) + } + + # Push the found/new class. + lookupNs->push_tail( declaredClass ) + declNs->push_tail( declaredClass ) + } + + | [class_key nested_name_specifier_opt templ_class_id + templ_arg_open template_argument_list_opt templ_arg_close] + { + match r3 [Id: lookup_id] + id: str = Id.data + classObj: lang_object = Id.obj + + # TODO: Try to find the specializaition in the template class object. + # TypeList typeList; + # makeTypeList( typeList $6->last ); + + declaredClass: lang_object + #declaredClass = classObj->findSpecExact( typeList ); + if !declaredClass { + # LOG print( 'making new template specialization\n' ) + nsType: int = declaredClassType() + declaredClass = createLangObject( nsType, id, lookupNs->tail ) + # LOG print( 'declaredClass: ' declaredClass '\n' ) + declaredClass->specializationOf = classObj + # $$->typeListMapEl = classObj->typeListMap.insert( typeList, declaredClass ); + } + + # Push the found/new class. + lookupNs->push_tail( declaredClass ) + declNs->push_tail( declaredClass ) + } + + def class_body_end + [] + { + # Pop the class ns. + lookupNs->pop_tail() + declNs->pop_tail() + + # LOG print( 'closing off class\n' ) + } + + def class_head_name + [class_id] + | [templ_class_id] + | [namespace_id] + | [typedef_id] + | [enum_id] + | [unknown_id] + | [identifier] + | [template_id] + + def class_key + [`class] + | [`struct] + | [`union] + + def class_member_rep + [class_member_rep class_member] + | [] + + def class_member + [member_declaration] + | [access_specifier `:] + + def member_declaration + [declaration_start member_declaration_forms declaration_end `;] + | [class_function_definition] + | [using_declaration] + | [template_declaration] + + def class_function_definition + [function_def_declaration ctor_initializer_opt class_function_body function_def_end] + + lex + token cfb_open /'{'/ + token cfb_close /'}'/ + token cfb_string / + "'" ( [^'\\\n] | '\\' any )* "'" | + '"' ( [^"\\\n] | '\\' any )* '"'/ + token cfb_comment / + ( '/*' (any | '\n')* :>> '*/' ) | + ( '//' any* :> '\n' )/ + token cfb_data /[^{}'"/]+ | '/'/ + end + + def cfb_item + [cfb_data] + | [cfb_string] + | [cfb_comment] + | [cfb_open cfb_item* cfb_close] + + def cfb_conts + [cfb_item* cfb_close] + + + + def class_function_body + # ['{' cfb_conts] + #| [function_body] + [function_body] + + # Get better performance if the form with decl_specifier_sing comes first. + def member_declaration_forms + [decl_specifier_mult_seq_opt decl_specifier_sing + decl_specifier_mult_seq_opt member_declarator_list_opt] + | [decl_specifier_mult_seq_opt member_declarator_list_opt] + + def member_declarator_list_opt + [member_declarator_list] + | [] + + def member_declarator_list + [member_declarator_list `, member_declarator] + | [member_declarator] + + def member_declarator + [declarator] + | [declarator `= constant_expression] + | [declarator `: constant_expression] + | [`: constant_expression] + + def access_specifier + [`private] + | [`protected] + | [`public] + + def access_specifier_opt + [access_specifier] + | [] + + def using_declaration + [`using id_expression `;] + { + obj: lang_object = r2.lookupId.obj + if obj + insertObject( declNs->tail, obj->name, obj ) + } + + | [`using type_id `;] + { + obj: lang_object = r2.lookupId.obj + if obj + insertObject( declNs->tail, obj->name, obj ) + } + + def using_directive + [`using `namespace root_qual_opt nested_name_specifier_opt + namespace_id `;] + { + # This uses a simple, incomplete guard against cycles in the graph of + # using namespaces. A more sophisticated and complete guard would look + # for longer cycles as well. Note that even gcc 3.3.5 does not bother. + match r5 [Id: lookup_id] + usingObject: lang_object = Id.obj + inObject: lang_object = declNs->tail + if usingObject != inObject + inObject->inherited->push_tail( usingObject ) + } + + + # + # Derived classes + # + + def base_clause_opt + [base_clause] + | [] + + def base_clause + [`: base_specifier_list] + + def base_specifier_list + [base_specifier_list `, base_specifier] + | [base_specifier] + + int addBaseSpecifier( inObject: lang_object, inheritedObject: lang_object ) + { + # Resolve typedefs. + if inheritedObject->typeId == TypedefType + inheritedObject = inheritedObject->typedefOf + + inObject->inherited->push_tail( inheritedObject ) + } + + def base_specifier + [root_qual_opt nested_name_specifier_opt type_name] + { + addBaseSpecifier( declNs->tail, r3.lookupId.obj ) + } + + | [`virtual access_specifier_opt root_qual_opt nested_name_specifier_opt type_name] + { + addBaseSpecifier( declNs->tail, r5.lookupId.obj ) + } + + | [access_specifier virtual_opt root_qual_opt nested_name_specifier_opt type_name] + { + addBaseSpecifier( declNs->tail, r5.lookupId.obj ) + } + + def virtual_opt + [`virtual] + | [] + + # + # Special member functions + # + + def conversion_function_id + [`operator conversion_type_id] + + def conversion_type_id + [necs_type_specifier_seq ptr_operator_seq_opt] + + def ctor_initializer_opt + [ctor_initializer] + | [] + + def ctor_initializer + [`: mem_initializer_list] + + def mem_initializer_list + [mem_initializer_list `, mem_initializer] + | [mem_initializer] + + def mem_initializer + [mem_initializer_id `( expression_opt `)] + + def mem_initializer_id + [root_qual_opt nested_name_specifier_opt unknown_id] + | [root_qual_opt nested_name_specifier_opt identifier] + | [root_qual_opt nested_name_specifier_opt type_name] + | [root_qual_opt nested_name_specifier_opt template_name] + + + # + # Overloading + # + def operator_function_id + [`operator operator] + + def operator + [`+] | [`-] | [`*] | [`/] | [`=] | [`<] | [`>] | [`&] | [`|] | + [`^] | [`%] | [`~] | [`!] | [`( `)] | [`[ `]] | [`new] | + [`delete] | [`->] | [`++] | [`--] | [`*=] | [`/=] | [`%=] | + [`+=] | [`-=] | [`>>=] | [`<<=] | [`&=] | [`^=] | [`|=] | [`==] | + [`!=] | [`&&] | [`||] | [lt_eq] | [gt_eq] | [shift_left] | [shift_right] + + def lt_eq + [`< `=] + # try { + # if ( $2->leader != 0 ) { + # #ifdef LOG_REDUCE + # cerr << "rejecting less-than equals-to" << endl; + # #endif + # reject(); + # } + # }; + + def gt_eq + [`> `=] + # try { + # if ( $2->leader != 0 ) { + # #ifdef LOG_REDUCE + # cerr << "rejecting greater-than equals-to" << endl; + # #endif + # reject(); + # } + # }; + + def shift_left + [`< `<] + # try { + # if ( $2->leader != 0 ) { + # #ifdef LOG_REDUCE + # cerr << "rejecting shift left" << endl; + # #endif + # reject(); + # } + # }; + + def shift_right + [`> `>] + # try { + # if ( $2->leader != 0 ) { + # #ifdef LOG_REDUCE + # cerr << "rejecting shift right" << endl; + # #endif + # reject(); + # } + # }; + + # + # Templates + # + + def template_declaration + [template_declaration_params declaration] + { + templDecl->pop_tail() + templateParamNs->pop_tail() + } + + def template_declaration_params + [`template `< tpl_start template_parameter_list `>] + { + templDecl->push_tail( 1 ) + } + + | [`export `template `< tpl_start template_parameter_list `>] + { + templDecl->push_tail( 1 ) + } + + def tpl_start + [] + { + # Create a new scope for the template parameters. + newTemplateParamScope: lang_object = + createLangObject( 0, '', lookupNs->tail ) + + templateParamNs->push_tail( newTemplateParamScope ) + } + + def template_parameter_list + [template_parameter_list `, template_parameter] + | [template_parameter] + + def template_parameter + [type_parameter] + | [template_parameter_declaration] + + def template_parameter_declaration + [declaration_start template_parameter_declaration_forms declaration_end] + + def template_parameter_declaration_forms + [decl_specifier_mult_seq param_maybe_declarator maybe_parameter_init] + + | [temp_param_decl_specifier_sing decl_specifier_mult_seq_opt + param_maybe_declarator maybe_parameter_init] + + | [decl_specifier_mult_seq temp_param_decl_specifier_sing + decl_specifier_mult_seq_opt param_maybe_declarator maybe_parameter_init] + + def temp_param_decl_specifier_sing + [temp_param_type_specifier_sing] + + # Template parameters cannot support elaborated type specifer or class specifier. + def temp_param_type_specifier_sing + [templ_simple_type_specifier] + | [enum_specifier] + + def templ_simple_type_specifier + [simple_type_specifier_name] + | [simple_type_specifier_kw_seq] + + def type_parameter + [`class type_param_id type_param_init_opt] + { + Id: lookup_id = lookup_id in r2 + if Id { + # The lookup ns should be a template param scope. + newClass: lang_object = + createLangObject( ClassType, Id.data, lookupNs->tail ) + insertObject( templateParamNs->tail, Id.data, newClass ) + } + } + + | [`typename type_param_id type_param_init_opt] + { + Id: lookup_id = lookup_id in r2 + if Id { + # The lookup ns should be a template param scope. + newClass: lang_object = + createLangObject( ClassType, Id.data, lookupNs->tail ) + insertObject( templateParamNs->tail, Id.data, newClass ) + } + } + + | [`template `< tpl_start template_parameter_list `> + `class type_param_id templ_type_param_init_opt] + { + Id: lookup_id = lookup_id in r7 + if Id { + newClass: lang_object = + createLangObject( TemplateClassType, Id.data, lookupNs->tail ) + insertObject( templateParamNs->tail, Id.data, newClass ) + } + } + + def templ_type_param_init_opt + [`= id_expression] + | [] + + def type_param_init_opt + [`= type_id] + | [] + + def type_param_id + [namespace_id] + | [typedef_id] + | [enum_id] + | [class_id] + | [templ_class_id] + | [identifier] + | [template_id] + | [unknown_id] + | [] + + def template_argument_list_opt + [template_argument_list] + | [] + + def template_argument_list + [template_argument_list `, template_argument] + | [template_argument] + + def template_argument + [type_id] + | [assignment_expression] + + def explicit_instantiation + [`template declaration] + | [declaration_start decl_specifier_mult_seq `template declaration declaration_end] + + def explicit_specialization + [`template `< `> declaration] + + ## Not sure what this one is about? + #explicit_specialization: + # declaration_start decl_specifier_mult_seq KW_Template '<' '>' + # declaration declaration_end; + + + # + # Original namespace definition + # + + def original_namespace_definition + [orig_namespace_def_name `{ declaration* namespace_end `}] + + def orig_namespace_def_name [`namespace unknown_id] + { + match r2 [Id: lookup_id] + nspace: lang_object = createLangObject( + NamespaceType, Id.data, lookupNs->tail ) + + # Insert the new object into the dictionary of the parent. + insertObject( curNamespace->tail, Id.data, nspace ) + + # Push the namespace + curNamespace->push_tail( nspace ) + declNs->push_tail( nspace ) + lookupNs->push_tail( nspace ) + + # LOG print( 'created original namespace: ' Id.data '\n' ) + } + + def namespace_end [] + { + # Pop the namespace. + curNamespace->pop_tail() + declNs->pop_tail() + lookupNs->pop_tail() + + # LOG print( 'closed namespace\n' ) + } + + # + # Extension namespace definition + # + + def extension_namespace_definition + [ext_namespace_def_name `{ declaration* namespace_end `}] + + def ext_namespace_def_name [`namespace namespace_id] + { + match r2 [Id: lookup_id] + nspace: lang_object = Id.obj + + # Push the namespace + curNamespace->push_tail( nspace ) + declNs->push_tail( nspace ) + lookupNs->push_tail( nspace ) + + # LOG print( 'found extended namespace: ' Id.data '\n' ) + } + + # + # Unnamed namespace definition + # + def unnamed_namespace_definition + [unnamed_namespace_def_name `{ declaration* namespace_end `}] + + def unnamed_namespace_def_name [`namespace] + { + nspace: lang_object = createLangObject( + NamespaceType, '', + lookupNs->tail ) + + # Push the namespace + curNamespace->push_tail( nspace ) + declNs->push_tail( nspace ) + lookupNs->push_tail( nspace ) + + # LOG print( 'parsed unnamed namespace\n' ) + } + + # + # linkage_specification + # + def linkage_specification + [`extern TK_DoubleLit `{ declaration* `}] + | [`extern TK_DoubleLit declaration] + + # + # Exception Handling. + # + + def try_block + [`try compound_statement handler_seq] + + def handler_seq + [handler_seq handler] + | [handler] + + def handler + [`catch `( exception_declaration `) compound_statement] + + def exception_declaration + [type_specifier_seq declarator] + | [type_specifier_seq abstract_declarator] + | [type_specifier_seq] + | [`...] + + def throw_expression + [`throw assignment_expression] + | [`throw] + + def exception_specification_opt + [exception_specification] + | [] + + def exception_specification + [`throw `( type_id_list_opt `)] + + def type_id_list_opt + [type_id_list] + | [] + + def type_id_list + [type_id_list `, type_id] + | [type_id] + + def start + [declaration*] + + # + # Grammar done. + # + + int printObject( indent: str, obj: lang_object ) + { + print( indent, obj->name ) + + if obj->objectMap->length > 0 + print( ' {\n' ) + + Map: map_list_lang_object = obj->objectMap + for List: list_lang_object in Map { + List2: list_lang_object = List + for Obj: lang_object in List2 { + printObject( indent + ' ', Obj ) + } + } + + + if obj->objectMap->length > 0 + print( indent, '}' ) + + print( '\n' ) + } + +end # lookup + +# +# Global data declarations +# + +Lookup: lookup = new lookup() + +# Constants for language object types. +Lookup->NamespaceType = typeid +Lookup->ClassType = typeid +Lookup->TemplateClassType = typeid +Lookup->EnumType = typeid +Lookup->IdType = typeid +Lookup->TypedefType = typeid +Lookup->TemplateIdType = typeid + + +# Object stacks. +Lookup->curNamespace = new lookup::list_lang_object() +Lookup->declNs = new lookup::list_lang_object() +Lookup->lookupNs = new lookup::list_lang_object() +Lookup->qualNs = new lookup::list_lang_object() +Lookup->templateParamNs = new lookup::list_lang_object() + +# Declaration, declarator data. +Lookup->declarationData = new lookup::list_declaration_data() +Lookup->declaratorData = new lookup::list_declarator_data() + +# Template declarations +Lookup->templDecl = new lookup::list_int() + +# Root namespace object +Lookup->rootNamespace = lookup::createLangObject( Lookup->NamespaceType, '', nil ) + +# Initialize the namespace and declaration stacks with the root namespace +Lookup->curNamespace->push_tail( Lookup->rootNamespace ) +Lookup->declNs->push_tail( Lookup->rootNamespace ) +Lookup->lookupNs->push_tail( Lookup->rootNamespace ) + +# Start with no qualification (note variables are initialized to zero) +Lookup->qualNs->push_tail( nil ) + +Lookup->templDecl->push_tail( 0 ) + +DD: lookup::declaration_data = new lookup::declaration_data() +DD->isTypedef = 0 +DD->isFriend = 0 +DD->isTemplate = 0 +Lookup->declarationData->push_tail( DD ) + +parse S: lookup::start( Lookup )[ stdin ] +if ! S { + print( error ) + exit( 1 ) +} + +print( '***** NAMSPACES *****\n' ) +lookup::printObject( '', Lookup->rootNamespace ) +print( '***** UNKNOWN DECLARATORS *****\n' ) +for DI: lookup::declarator_id in S { + if match DI + [lookup::root_qual_opt lookup::nested_name_specifier_opt lookup::`~ UID: lookup::unknown_id] + { + print( UID, '\n' ) + } +} diff --git a/grammar/c++/expected b/grammar/c++/expected new file mode 100644 index 00000000..4757e9e2 --- /dev/null +++ b/grammar/c++/expected @@ -0,0 +1,74 @@ +***** NAMSPACES ***** + { + A { + B + } + B { + Find + } + C { + D + } + C + C + C + C { + j + } + C + C + C + C { + D + I + i + } + C { + find + } + C { + D + g + } + C { + D + f + } + D + E + E + T + Y { + Z + f + t + } + a + b + b + c + c + d + e + f + f + f + i + i + Int + ns1 { + sub1 { + A + } + sub2 { + B + } + } + ns2 { + C + i + } + function +} +***** UNKNOWN DECLARATORS ***** +C diff --git a/grammar/c++/input.cc b/grammar/c++/input.cc new file mode 100644 index 00000000..83d51071 --- /dev/null +++ b/grammar/c++/input.cc @@ -0,0 +1,153 @@ +namespace ns1 +{ + namespace sub1 { class A {}; } + namespace sub2 { class B {}; } +} + +namespace ns2 +{ + int i = b; + class C + { + }; + + using namespace ns1; +} + +ns2::sub1::A a; + +struct A +{ + struct B {}; +}; + +struct C +{ + struct D : virtual public A {}; +}; + +C::D::A d; + +C c; + +struct C +{ + +}; + +enum E +{ + C, + b +}; + +E e; + +enum E +{ + C, + b +}; + + +int i; +class C +{ + int j; +}; + +class D +{ + int ~D(); +}; + +int C::k; +int C::~C; + +typedef int Int; + +class C {}; +void ~C( ); +void C::operator +( int i ); + +int i; + +//void operator C( void k ); + +class C +{ + +}; + +int C::f( int i, int j( void v ) ); +class C +{ + class D {}; + + typedef C I; + + I::D i; +}; + +C c; + +void function( int i, int j ) +{ + function(); +} + + + +class B { class Find {}; }; + +typedef B T; + +class C : public T +{ + Find find; +}; + + +template struct Y +{ + X t; + void f(); +}; + +template void Y::f(); +template struct Y +{ + class Z {}; +}; + +class Y +{ + int i; +}; + +//void f( class C i, int j ); + +int f( int (*) [](), void ); +void f(); +class C +{ + class D {}; + void g(); +}; + +//typename C c; + +class C +{ + class D {}; + int f(); +}; + +int f() +{ +} + +int C::f() +{ + D d; +} diff --git a/grammar/pcre/Makefile b/grammar/pcre/Makefile index 6f895485..538d0220 100644 --- a/grammar/pcre/Makefile +++ b/grammar/pcre/Makefile @@ -7,5 +7,5 @@ pcre-colm: pcre.lm $(COLM) -o $@ pcre.lm pcre-ragel: pcre.rl $(RAGEL) - $(RAGEL) -G2 pcre.rl - gcc -g -Wall -o $@ pcre.c + $(RAGEL) -G2 -o pcre-ragel.c pcre.rl + gcc -g -Wall -o $@ pcre-ragel.c diff --git a/grammar/python/.gitignore b/grammar/python/.gitignore new file mode 100644 index 00000000..f62062c6 --- /dev/null +++ b/grammar/python/.gitignore @@ -0,0 +1,2 @@ +/python.c +/python diff --git a/grammar/python/Makefile b/grammar/python/Makefile new file mode 100644 index 00000000..555b9d28 --- /dev/null +++ b/grammar/python/Makefile @@ -0,0 +1,7 @@ +COLM = ../../colm/colm +RAGEL = ../../ragel/ragel + +all: python + +python: python.lm + $(COLM) -o $@ $< diff --git a/grammar/python/expected b/grammar/python/expected new file mode 100644 index 00000000..813aeb5b --- /dev/null +++ b/grammar/python/expected @@ -0,0 +1,137 @@ +*** SUCCESS *** + +hello +def dude(): + yes + awesome; + + # Here we have a comment + def realy_awesome(): # hi there + in_more + + same_level + def one_liner(): first; second # both inside one_liner + + back_down + +last_statement + +# dude, this is a comment + # some more +hello +if 1: + yes + awesome; + + # Here we have a comment + if ('hello'): # hi there + in_more + + same_level + if ['dude', 'dudess'].horsie(): first; second # both inside one_liner + 1 + + back_down + +last_statement + +hello = 1.1(20); + +# subscription +a[1] = b[2]; + +# simple slicing +c[1:1] = d[2:2]; + +# simple slicing +e[1:1, 2:2] = f[3:3, 4:4]; +*** +STMT: hello +STMT: def dude(): + yes + awesome; + + # Here we have a comment + def realy_awesome(): # hi there + in_more + + same_level + def one_liner(): first; second # both inside one_liner + + back_down + +STMT: yes +STMT: awesome; + + # Here we have a comment +STMT: def realy_awesome(): # hi there + in_more + + same_level + def one_liner(): first; second # both inside one_liner + +STMT: in_more + +STMT: same_level +STMT: def one_liner(): first; second # both inside one_liner + +STMT: back_down + +STMT: last_statement + +# dude, this is a comment + # some more +STMT: hello +STMT: if 1: + yes + awesome; + + # Here we have a comment + if ('hello'): # hi there + in_more + + same_level + if ['dude', 'dudess'].horsie(): first; second # both inside one_liner + 1 + + back_down + +STMT: yes +STMT: awesome; + + # Here we have a comment +STMT: if ('hello'): # hi there + in_more + + same_level + if ['dude', 'dudess'].horsie(): first; second # both inside one_liner + 1 + +STMT: in_more + +STMT: same_level +STMT: if ['dude', 'dudess'].horsie(): first; second # both inside one_liner +STMT: 1 + +STMT: back_down + +STMT: last_statement + +STMT: hello = 1.1(20); + +# subscription +STMT: a[1] = b[2]; + +# simple slicing +STMT: c[1:1] = d[2:2]; + +# simple slicing +STMT: e[1:1, 2:2] = f[3:3, 4:4]; +TARGET SUBSCRIPTION: [1] +TARGET SIMPLE SLICING: [1:1] +TARGET EXTENDED SLICING: [1:1, 2:2] +PRIMARY SUBSCRIPTION: [2] +PRIMARY SIMPLE SLICING: [2:2] +PRIMARY EXTENDED SLICING: [3:3, 4:4] +*** SUCCESS *** + diff --git a/grammar/python/input.py b/grammar/python/input.py new file mode 100644 index 00000000..a6380068 --- /dev/null +++ b/grammar/python/input.py @@ -0,0 +1,47 @@ +# dude, this is a comment + # some more +hello +def dude(): + yes + awesome; + + # Here we have a comment + def realy_awesome(): # hi there + in_more + + same_level + def one_liner(): first; second # both inside one_liner + + back_down + +last_statement + +# dude, this is a comment + # some more +hello +if 1: + yes + awesome; + + # Here we have a comment + if ('hello'): # hi there + in_more + + same_level + if ['dude', 'dudess'].horsie(): first; second # both inside one_liner + 1 + + back_down + +last_statement + +hello = 1.1(20); + +# subscription +a[1] = b[2]; + +# simple slicing +c[1:1] = d[2:2]; + +# simple slicing +e[1:1, 2:2] = f[3:3, 4:4]; diff --git a/grammar/python/python.lm b/grammar/python/python.lm new file mode 100644 index 00000000..ac3c8071 --- /dev/null +++ b/grammar/python/python.lm @@ -0,0 +1,579 @@ +context generate + # Regular definitions + rl ident_char /[a-zA-Z_]/ + + # List used as a stack of indentations. + IndentStack: list + + # Has a newline been sent for this '\n' .. whitespace match. + newline_sent: int + + # Tokens. + lex + # Python keywords. + literal `and `del `from `not `while `as `elif `global `or + `with `assert `else `if `pass `yield `break `except + `import `print `class `exec `in `raise `continue + `finally `is `return `def `for `lambda `try + + # Identifiers + rl lowercase /'a'..'z'/ + rl uppercase /'A'..'Z'/ + rl letter /lowercase | uppercase/ + token identifier /(letter|'_') (letter | digit | '_')*/ + + # Literals + rl escapeseq /'\\' any / + rl longstringchar /[^\\]/ + rl shortstringchar_s /[^\\\n']/ + rl shortstringchar_d /[^\\\n"]/ + rl longstringitem /longstringchar | escapeseq/ + rl shortstringitem_s /shortstringchar_s | escapeseq/ + rl shortstringitem_d /shortstringchar_d | escapeseq/ + rl longstring /"'''" longstringitem* :>> "'''" | '"""' longstringitem* :>> '"""'/ + rl shortstring /"'" shortstringitem_s* "'" | '"' shortstringitem_d* '"'/ + rl stringprefix /"r" | "u" | "ur" | "R" | "U" | "UR" | "Ur" | "uR"/ + token stringliteral /stringprefix? (shortstring | longstring)/ + + # Integers + rl hexdigit /digit | 'a'..'f' | 'A'..'F'/ + rl octdigit /'0'..'7'/ + rl nonzerodigit /'1'..'9'/ + rl hexinteger /'0' ('x' | 'X') hexdigit+/ + rl octinteger /'0' octdigit+/ + rl decimalinteger /nonzerodigit digit* | '0'/ + token integer /decimalinteger | octinteger | hexinteger/ + token longinteger /integer ('l' | 'L')/ + + # Floats. + rl exponent /('e' | 'E') ('+' | '-')? digit+/ + rl fraction /'.' digit+/ + rl intpart /digit+/ + rl pointfloat /intpart? fraction | intpart '.'/ + rl exponentfloat /(intpart | pointfloat) exponent/ + token floatnumber /pointfloat | exponentfloat/ + + # Imaginaries. + token imagnumber /(floatnumber | intpart) ("j" | "J")/ + + # Operators. + literal `+ `- `* `** `/ `// `% `<< `>> `& `| `^ + `~ `< `> `<= `>= `== `!= `<> + + # Delimiters + literal `( `) `[ `] `{ `} `@ `, `: `. `` `= `; + `+= `-= `*= `/= `//= `%= `&= `|= `^= `>>= `<<= + `**= + + literal `... + + # In general whitespace is ignored. + ignore WS /' '+/ + + # Find and ignore entire blank lines. + token BLANK_LINE + / '\n' [ \t]* ('#' [^\n]*)? '\n' / + { + # Need to shorten to take off the newline. + # Turn it into ignore. + input->push_ignore( make_token( typeid, input->pull(match_length - 1) ) ) + } + + # Find and ignore comments. + token COMMENT + / '#' [^\n]* '\n' / + { + # Need to shorten to take off the newline. Turn it into ignore. + input->push_ignore( make_token( typeid, input->pull(match_length - 1) ) ) + } + + # These tokens are generated + token INDENT // + token DEDENT // + token NEWLINE // + ignore IND_WS // + + token INDENTATION + /'\n' [ \t]*/ + { + # We have squared up INDENTs and DEDENTs. Ignore the entire match. + input->push_ignore( make_token( typeid, input->pull(match_length) ) ) + + # We have already sent the newline, compute the indentation level. + data_length: int = match_length - 1 + + Top: int = IndentStack->top + if data_length > Top { + # The indentation level is more than the level on the top + # of the stack. This is an indent event. Send as an INDENT. + input->push( make_token( typeid, '' ) ) + + # Push to the stack as per python manual. + IndentStack->push( data_length ) + } else { + while data_length < Top { + # The indentation level is less than the level on the top of + # the stack. Pop the level and send one dedent. This flow of + # control will execute until we find the right indentation level + # to match up with. + IndentStack->pop() + + # Send as a DEDENT + input->push( make_token( typeid, '' ) ) + + Top = IndentStack->top + } + } + + # FIXME: if data.length is now > top of stack then error. This + # means the outdent does not match anything. + + # First the newline. + input->push( make_token( typeid, '' ) ) + } + end + + # Blank lines or comment lines at the beginning of the file. + token LEADER / ( [ \t]* ('#' [^\n]*)? '\n' )* / + + # Ordering productions for resolving ambiguities. + def O1 [] + def O2 [] + + def start + [file_input] + + def file_input + [file_input_forms*] + + def file_input_forms + [statement] + | [NEWLINE] + + def statement + [stmt_list NEWLINE] + | [compound_stmt] + + def stmt_list + [simple_stmt another_stmt* opt_semi] + + def another_stmt + [`; simple_stmt] + + def opt_semi + [`;] + | [] + + def suite + [stmt_list NEWLINE] + | [NEWLINE INDENT statement_seq DEDENT] + + def statement_seq + [statement_seq statement] + | [statement] + + def compound_stmt + [if_stmt] + | [while_stmt] + | [for_stmt] + | [funcdef] + + def if_stmt + [`if expression `: suite elif_part* opt_else_part] + + def elif_part + [`elif expression `: suite] + + def opt_else_part + [`else `: suite] + | [] + + def while_stmt + [`while expression `: suite opt_else_part] + + def for_stmt + [`for target_list `in expression_list `: suite opt_else_part] + + def funcdef + [`def funcname `( opt_parameter_list `) `: suite] + + def funcname + [identifier] + + def dotted_name + [dotted_name `. identifier] + | [identifier] + + def opt_parameter_list + [parameter_list] + | [] + + def parameter_list + [defparameter_list defparameter opt_comma] + + def defparameter_list + [defparameter_list defparameter `,] + | [] + + def defparameter + [parameter] + | [parameter `= expression] + + def sublist + [sublist_pl opt_comma] + + def sublist_pl + [sublist_pl `, parameter] + | [parameter] + + def parameter + [identifier] + | [`( sublist `)] + + def classname + [identifier] + + def simple_stmt + [expression_stmt] + | [assignment_stmt] + | [print_stmt] + + def expression_stmt + [expression_list] + + def assignment_stmt + [target_equals_list expression_list] + + def target_equals_list + [target_equals_list target_equals] + | [target_equals] + + def target_equals + [target_list `=] + + def target_list + [target_list_core opt_comma] + + def target_list_core + [target_list_core `, target] + | [target] + + def target + [target_atom target_ext_rep] + + def target_atom + [identifier] + | [`( target_list `)] + | [`[ target_list `]] + + def target_ext_rep + [target_ext target_ext_rep] + | [] + + def target_ext + [attributeref] + | [O1 subscription] + | [O2 slicing] + + def print_stmt + [`print opt_expression_list] + + def opt_expression_list + [expression_list] + | [] + + def expression_list + [expression_list_core opt_comma] + + def expression_list_core + [expression_list_core `, expression] + | [expression] + + def opt_comma + [`,] + | [] + + def expression + [or_test `if or_test `else test] + | [or_test] + | [lambda_form] + + def or_test + [or_test `or and_test] + | [and_test] + + def and_test + [and_test `and not_test] + | [not_test] + + def not_test + [comparison] + | [`not not_test] + + def lambda_form + [`lambda opt_parameter_list `: expression] + + def test + [or_test] + | [lambda_form] + + def comparison + [or_expr comparison_part*] + + def comparison_part + [comp_operator or_expr] + + def comp_operator + [`<] | [`>] | [`==] | [`>=] | [`<=] | [`<>] | [`!=] | [`is] | + [`is `not] | [`in] | [`not `in] + + def or_expr + [primary] + + def primary + [atom primary_ext_rep] + + def atom + [identifier] + | [pyliteral] + | [enclosure] + + def primary_ext_rep + [primary_ext primary_ext_rep] + | [] + + def primary_ext + [attributeref] + | [O1 subscription] + | [O2 slicing] + | [call] + + def pyliteral + [stringliteral] + | [integer] + | [longinteger] + | [floatnumber] + | [imagnumber] + + def enclosure + [parenth_form] + | [list_display] + | [generator_expression] + | [dict_display] + | [string_conversion] + + def parenth_form + [`( opt_expression_list `)] + + def list_display + [`[ opt_listmaker `]] + + def opt_listmaker + [listmaker] + | [] + + def listmaker + [expression list_for] + | [expression listmaker_ext* opt_comma] + + def listmaker_ext + [`, expression] + + def opt_list_iter + [list_iter] + | [] + + def list_iter + [list_for] + | [list_if] + + def list_if + [`if test opt_list_iter] + + def list_for + [`for expression_list `in testlist opt_list_iter] + + def testlist + [test testlist_ext* opt_comma] + + def testlist_ext + [`, test ] + + def generator_expression + [`( test genexpr_for `)] + + def genexpr_for + [`for expression_list `in test opt_genexpr_iter] + + def opt_genexpr_iter + [genexpr_iter] + | [] + + def genexpr_iter + [genexpr_for] + | [genexpr_if] + + def genexpr_if + [`if test opt_genexpr_iter] + + def dict_display + [`{ opt_key_datum_list `}] + + def opt_key_datum_list + [key_datum_list] + | [] + + def key_datum_list + [key_datum key_datum_list_ext* opt_comma] + + def key_datum_list_ext + [`, key_datum] + + def key_datum + [expression `: expression] + + def string_conversion + [`` expression_list ``] + + def attributeref + [`. identifier] + + def subscription + [`[ expression_list `]] + + # The natural ordered choice does not suffice here. Must force it. + + def slicing + [simple_slicing] + | [extended_slicing] + + def simple_slicing + [`[ short_slice `]] + + def extended_slicing + [`[ slice_list `]] + + def slice_list + [slice_item slice_list_ext* opt_comma] + + def slice_list_ext + [`, slice_item] + + def slice_item + [expression] + | [proper_slice] + | [ellipsis] + + def proper_slice + [short_slice] + | [long_slice] + + def short_slice + [`:] + | [`: upper_bound] + | [lower_bound `:] + | [lower_bound `: upper_bound] + + def long_slice + [short_slice `: stride] + | [short_slice `:] + + def lower_bound + [expression] + + def upper_bound + [expression] + + def stride + [expression] + + def ellipsis + [`...] + + def call + [`( opt_argument_list `)] + + def opt_argument_list + [argument_list opt_comma] + | [] + + def argument_list + [positional_arguments opt_comma_keyword_arguments] + | [keyword_arguments] + + def positional_arguments + [positional_arguments `, expression] + | [expression] + + def opt_comma_keyword_arguments + [`, keyword_arguments] + | [] + + def keyword_arguments + [keyword_arguments `, keyword_item] + | [keyword_item] + + def keyword_item + [identifier `= expression] + +end # generate + +int print_stmts( S: generate::start ) +{ + for Stmt: generate::statement in S + print[ 'STMT: ' ^Stmt '\n' ] +} + +int print_target_subscriptions_and_slicings( Start: generate::start ) +{ + for TI: generate::target_ext in Start { + if match TI [generate::subscription] { + print[ 'TARGET SUBSCRIPTION: ' ^TI '\n' ] + } + + if match TI [generate::simple_slicing] { + print[ 'TARGET SIMPLE SLICING: ' ^TI '\n' ] + } + + if match TI [generate::extended_slicing] { + print[ 'TARGET EXTENDED SLICING: ' ^TI '\n' ] + } + } + +} + +int print_primary_subscriptions_and_slicings( Start: generate::start ) +{ + for PI: generate::primary_ext in Start { + if match PI [generate::subscription] { + print[ 'PRIMARY SUBSCRIPTION: ' ^PI '\n' ] + } + + if match PI [generate::simple_slicing] { + print[ 'PRIMARY SIMPLE SLICING: ' ^PI '\n' ] + } + + if match PI [generate::extended_slicing] { + print[ 'PRIMARY EXTENDED SLICING: ' ^PI '\n' ] + } + } +} + +Generate: generate = new generate() + +# List used as a stack of indentations. +Generate->IndentStack = new list() +Generate->IndentStack->push( 0 ) + +# Has a newline been sent for this '\n' .. whitespace match. +Generate->newline_sent = 0 + +parse S: generate::start(Generate)[ stdin ] + +print[ '*** SUCCESS ***\n' ] +print[ ^S '\n' ] +print[ '***\n' ] +print_stmts( S ) +print_target_subscriptions_and_slicings( S ) +print_primary_subscriptions_and_slicings( S ) +print( '*** SUCCESS ***\n' ) -- cgit v1.2.1