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' ) } }