/* * Copyright 2006-2012 Adrian Thurston */ /* This file is part of Colm. * * Colm is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Colm is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Colm; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include "config.h" #include "lmparse.h" #include "global.h" #include "input.h" #include "fsmrun.h" using std::cout; using std::cerr; using std::endl; ParserDict parserDict; %%{ parser ColmParser; include "lmparse.kh"; start: root_item_list final { if ( colm_log_compile ) { cerr << "parsing complete" << endl; } pd->rootCodeBlock = new CodeBlock( $1->stmtList ); }; nonterm root_item_list uses lang_stmt_list; root_item_list: root_item_list root_item final { $$->stmtList = $1->stmtList; /* Maybe a statement. */ if ( $2->stmt != 0 ) $$->stmtList->append( $2->stmt ); }; root_item_list: final { $$->stmtList = new StmtList; }; nonterm root_item uses statement; root_item: literal_def commit final { $$->stmt = 0; }; root_item: rl_def commit final { $$->stmt = 0; }; root_item: token_def commit final { $$->stmt = 0; }; root_item: cfl_def commit final { $$->stmt = 0; }; root_item: region_def commit final { $$->stmt = 0; }; root_item: context_def commit final { $$->stmt = 0; }; root_item: namespace_def commit final { $$->stmt = 0; }; root_item: function_def commit final { $$->stmt = 0; }; root_item: iter_def commit final { $$->stmt = 0; }; root_item: global_def commit final { $$->stmt = $1->stmt; }; root_item: statement commit final { $$->stmt = $1->stmt; }; root_item: pre_eof commit final { $$->stmt = 0; }; root_item: precedence commit final { $$->stmt = 0; }; root_item: typedef commit final { $$->stmt = 0; }; nonterm block_open { ObjectDef *localFrame; }; block_open: '{' final { /* Init the object representing the local frame. */ $$->localFrame = new ObjectDef( ObjectDef::FrameType, "local", pd->nextObjectId++ ); pd->curLocalFrame = $$->localFrame; /* Add captures to the local frame. We Depend on these becoming the * first local variables so we can compute their location. */ /* Make local variables corresponding to the local capture vector. */ for ( ReCaptureVect::Iter c = reCaptureVect; c.lte(); c++ ) { ObjField *objField = new ObjField( c->objField->loc, c->objField->typeRef, c->objField->name ); /* Insert it into the field map. */ pd->curLocalFrame->insertField( objField->name, objField ); } }; block_close: '}' final { /* Pop the cur local frame, back to the root. */ pd->curLocalFrame = pd->rootLocalFrame; }; iter_def: KW_Iter TK_Word '(' opt_param_list ')' block_open lang_stmt_list block_close final { CodeBlock *codeBlock = new CodeBlock( $7->stmtList ); codeBlock->localFrame = $6->localFrame; Function *newFunction = new Function( 0, $2->data, $4->paramList, codeBlock, pd->nextFuncId++, true ); pd->functionList.append( newFunction ); }; function_def: type_ref TK_Word '(' opt_param_list ')' block_open lang_stmt_list block_close final { CodeBlock *codeBlock = new CodeBlock( $7->stmtList ); codeBlock->localFrame = $6->localFrame; Function *newFunction = new Function( $1->typeRef, $2->data, $4->paramList, codeBlock, pd->nextFuncId++, false ); pd->functionList.append( newFunction ); if ( contextStack.length() > 0 ) newFunction->inContext = contextStack.top(); }; nonterm opt_param_list uses param_list; opt_param_list: param_list final { $$->paramList = $1->paramList; }; opt_param_list: final { $$->paramList = new ParameterList; }; nonterm param_list { ParameterList *paramList; }; param_list: param_list param_var_def final { $$->paramList = $1->paramList; $$->paramList->append( $2->objField ); }; param_list: param_var_def final { /* Create the map and insert the first item. */ $$->paramList = new ParameterList; $$->paramList->append( $1->objField ); }; nonterm param_var_def uses var_def; param_var_def: TK_Word ':' type_ref final { $$->objField = new ObjField( $1->loc, $3->typeRef, $1->data ); $$->objField->isParam = true; }; param_var_def: TK_Word ':' reference_type_ref final { $$->objField = new ObjField( $1->loc, $3->typeRef, $1->data ); $$->objField->isParam = true; }; nonterm reference_type_ref uses type_ref; reference_type_ref: KW_Ref type_ref final { $$->typeRef = TypeRef::cons( TypeRef::Ref, $1->loc, $2->typeRef ); }; nonterm global_def uses statement; global_def: KW_Export var_def opt_def_init final { $$->stmt = 0; if ( contextStack.length() != 0 ) error($2->objField->loc) << "cannot export parser context variables" << endp; ObjectDef *object = pd->globalObjectDef; if ( object->checkRedecl( $2->objField->name ) != 0 ) error($2->objField->loc) << "object field renamed" << endp; object->insertField( $2->objField->name, $2->objField ); $2->objField->isExport = true; if ( $3->expr != 0 ) { LangVarRef *varRef = new LangVarRef( $2->objField->loc, new QualItemVect, $2->objField->name ); $$->stmt = LangStmt::cons( $2->objField->loc, $3->assignType, varRef, $3->expr ); } }; global_def: KW_Global var_def opt_def_init final { $$->stmt = 0; ObjectDef *object; if ( contextStack.length() == 0 ) object = pd->globalObjectDef; else { Context *context = contextStack.top(); $2->objField->context = context; object = context->contextObjDef; } if ( object->checkRedecl( $2->objField->name ) != 0 ) error($2->objField->loc) << "object field renamed" << endp; object->insertField( $2->objField->name, $2->objField ); if ( $3->expr != 0 ) { LangVarRef *varRef = new LangVarRef( $2->objField->loc, new QualItemVect, $2->objField->name ); $$->stmt = LangStmt::cons( $2->objField->loc, $3->assignType, varRef, $3->expr ); } }; precedence: pred_type pred_token_list final { pd->predValue++; }; pred_type: KW_Left final { predType = PredLeft; }; pred_type: KW_Right final { predType = PredRight; }; pred_type: KW_Nonassoc final { predType = PredNonassoc; }; pred_token_list: pred_token_list ',' pred_token final { }; pred_token_list: pred_token; nonterm pred_token { ProdEl *factor; TypeRef *typeRef; }; pred_token: region_qual TK_Word final { TypeRef *typeRef = TypeRef::cons( $2->loc, $1->nspaceQual, $2->data ); PredDecl *predDecl = new PredDecl( typeRef, predType, pd->predValue ); pd->predDeclList.append( predDecl ); }; pred_token: region_qual TK_Literal final { PdaLiteral *literal = new PdaLiteral( $2->loc, *$2 ); TypeRef *typeRef = TypeRef::cons( $2->loc, $1->nspaceQual, literal ); PredDecl *predDecl = new PredDecl( typeRef, predType, pd->predValue ); pd->predDeclList.append( predDecl ); }; typedef: KW_Alias TK_Word type_ref final { Namespace *nspace = namespaceStack.top(); TypeAlias *typeAlias = new TypeAlias( $1->loc, nspace, $2->data, $3->typeRef ); nspace->typeAliasList.append( typeAlias ); }; cfl_def: cfl_def_head obj_var_list properties_list cfl_prod_list final { Namespace *nspace = namespaceStack.top(); NtDef *ntDef = new NtDef( curDefineId, nspace, $4->defList, pd->objectDef, contextStack.length() > 0 ? contextStack.top() : 0, $3->property & PROPERTY_REDUCE_FIRST ); nspace->ntDefList.append( ntDef ); }; cfl_def_head: KW_Def TK_Word final { curDefineId = $2->data; curDefList = new LelDefList; }; nonterm cfl_prod_list { LelDefList *defList; }; cfl_prod_list: cfl_prod_list '|' define_prod final { $$->defList = $1->defList; $3->definition->prodNum = $$->defList->length(); $$->defList->append( $3->definition ); }; cfl_prod_list: define_prod final { $$->defList = curDefList; $1->definition->prodNum = $$->defList->length(); $$->defList->append( $1->definition ); }; nonterm property { long property; }; nonterm properties_list uses property; properties_list: properties_list property final { $$->property = $1->property | $2->property; }; properties_list: final { $$->property = 0; }; property: KW_ReduceFirst final { $$->property = PROPERTY_REDUCE_FIRST; }; nonterm opt_prec { LangEl *predOf; }; opt_prec: final { $$->predOf = 0; }; opt_prec: KW_Prec pred_token final { $$->predOf = $2->factor->langEl; }; nonterm define_prod { Definition *definition; }; define_prod: '[' prod_el_list ']' opt_commit opt_reduce_code opt_prec final { const InputLoc &loc = $1->loc; //const String &name = curDefineId; ProdElList *prodElList = curProdElList; bool commit = $4->commit; CodeBlock *redBlock = $5->codeBlock; LangEl *predOf = $6->predOf; //Namespace *nspace = namespaceStack.top(); Definition *newDef = new Definition( loc, 0/*prodName*/, prodElList, commit, redBlock, pd->prodList.length(), 0, Definition::Production ); newDef->predOf = predOf; pd->prodList.append( newDef ); $$->definition = newDef; }; obj_var_list: obj_var_list var_def final { if ( pd->objectDef->checkRedecl( $2->objField->name ) != 0 ) error() << "object field renamed" << endp; pd->objectDef->insertField( $2->objField->name, $2->objField ); }; obj_var_list: final { pd->objectDef = new ObjectDef( ObjectDef::UserType, curDefineId, pd->nextObjectId++ ); }; nonterm type_ref { TypeRef *typeRef; }; type_ref: basic_type_ref final { $$->typeRef = $1->typeRef; }; type_ref: KW_Map '<' type_ref type_ref '>' final { NamespaceQual *nspaceQual = new NamespaceQual( namespaceStack.top(), regionStack.top() ); $$->typeRef = TypeRef::cons( TypeRef::Map, InputLoc(), nspaceQual, $3->typeRef, $4->typeRef ); }; type_ref: KW_List '<' type_ref '>' final { NamespaceQual *nspaceQual = new NamespaceQual( namespaceStack.top(), regionStack.top() ); $$->typeRef = TypeRef::cons( TypeRef::List, InputLoc(), nspaceQual, $3->typeRef, 0 ); }; type_ref: KW_Vector '<' type_ref '>' final { NamespaceQual *nspaceQual = new NamespaceQual( namespaceStack.top(), regionStack.top() ); $$->typeRef = TypeRef::cons( TypeRef::Vector, InputLoc(), nspaceQual, $3->typeRef, 0 ); }; type_ref: KW_Accum '<' type_ref '>' final { NamespaceQual *nspaceQual = new NamespaceQual( namespaceStack.top(), regionStack.top() ); $$->typeRef = TypeRef::cons( TypeRef::Parser, InputLoc(), nspaceQual, $3->typeRef, 0 ); }; nonterm basic_type_ref uses type_ref; basic_type_ref: region_qual TK_Word opt_repeat final { $$->typeRef = TypeRef::cons( $2->loc, $1->nspaceQual, $2->data ); $$->typeRef->repeatType = $3->repeatType; }; basic_type_ref: KW_Ptr region_qual TK_Word opt_repeat final { $$->typeRef = TypeRef::cons( $1->loc, $2->nspaceQual, $3->data ); $$->typeRef->repeatType = $4->repeatType; $$->typeRef = TypeRef::cons( TypeRef::Ptr, $1->loc, $$->typeRef ); }; nonterm var_def { InputLoc loc; ObjField *objField; }; var_def: TK_Word ':' type_ref final { /* Return an object field object. The user of this nonterminal must * load it into the approrpriate map and do error checking. */ $$->objField = new ObjField( $1->loc, $3->typeRef, $1->data ); }; region_def: region_head '{' root_item_list '}' final { /* Pop the top of the stack. */ regionStack.pop(); }; region_head: KW_Lex TK_Word final { /* Just for ignores. */ String scannerNameIgn( $2->data.length() + 2, "<%s>-ign", $2->data.data ); TokenRegion *tokenRegionIgn = createRegion( scannerNameIgn ); /* Just for collect ignores. Will use the ignore-only start state. */ String scannerNameCi( $2->data.length() + 2, "<%s>-ci", $2->data.data ); TokenRegion *tokenRegionCi = createRegion( scannerNameCi ); /* Just for tokens. */ String scannerNameTok( $2->data.length() + 2, "<%s>-tok", $2->data.data ); TokenRegion *tokenRegionTok = createRegion( scannerNameTok ); /* Make the new token region. */ String scannerName( $2->data.length() + 2, "<%s>", $2->data.data ); TokenRegion *tokenRegion = createRegion( scannerName ); regionStack.push( tokenRegion ); tokenRegion->ignoreOnlyRegion = tokenRegionIgn; tokenRegion->tokenOnlyRegion = tokenRegionTok; tokenRegion->ciRegion = tokenRegionCi; tokenRegion->isFullRegion = true; tokenRegionIgn->isIgnoreOnly = true; tokenRegionCi->isCiOnly = true; tokenRegionTok->isTokenOnly = true; tokenRegionIgn->derivedFrom = tokenRegion; tokenRegionCi->derivedFrom = tokenRegion; tokenRegionTok->derivedFrom = tokenRegion; }; namespace_def: namespace_head '{' root_item_list '}' final { namespaceStack.pop(); }; namespace_head: KW_Namespace TK_Word final { /* Make the new namespace. */ Namespace *nspace = new Namespace( InputLoc(), $2->data, pd->namespaceList.length(), namespaceStack.top() ); namespaceStack.top()->childNamespaces.append( nspace ); pd->namespaceList.append( nspace ); namespaceStack.push( nspace ); }; context_var_def: var_def final { ObjectDef *object; if ( contextStack.length() == 0 ) error($1->loc) << "internal error: no context stack items found" << endp; Context *context = contextStack.top(); $1->objField->context = context; object = context->contextObjDef; if ( object->checkRedecl( $1->objField->name ) != 0 ) error($1->objField->loc) << "object field renamed" << endp; object->insertField( $1->objField->name, $1->objField ); }; context_item: context_var_def commit; context_item: literal_def commit; context_item: rl_def commit; context_item: token_def commit; context_item: cfl_def commit; context_item: region_def commit; context_item: context_def commit; context_item: function_def commit; context_item: iter_def commit; context_item: pre_eof commit; context_item: precedence commit; context_item_list: context_item_list context_item; context_item_list: ; context_def: context_head '{' context_item_list '}' final { contextStack.pop(); namespaceStack.pop(); }; context_head: KW_Context TK_Word final { /* Make the new namespace. */ Namespace *nspace = new Namespace( InputLoc(), $2->data, pd->namespaceList.length(), namespaceStack.top() ); namespaceStack.top()->childNamespaces.append( nspace ); pd->namespaceList.append( nspace ); namespaceStack.push( nspace ); Context *context = new Context( $1->loc, 0 ); contextStack.push( context ); ContextDef *contextDef = new ContextDef( $2->data, context, nspace ); nspace->contextDefList.append( contextDef ); context->contextObjDef = new ObjectDef( ObjectDef::UserType, $2->data, pd->nextObjectId++ ); }; pattern_list: pattern_list pattern; pattern_list: init_pattern_list pattern; init_pattern_list: final { patternItemList = new PatternItemList; }; pattern: '"' litpat_el_list '"'; pattern: '[' pattern_el_list ']'; litpat_el_list: litpat_el_list litpat_el; litpat_el_list: ; litpat_el: TK_LitPat final { PatternItem *patternItem = PatternItem::cons( $1->loc, $1->data, PatternItem::InputText ); patternItemList->append( patternItem ); }; litpat_el: '[' pattern_el_list ']'; pattern_el_list: pattern_el_list pattern_el; pattern_el_list: ; pattern_el: opt_label pattern_el_type_or_lit final { /* Store the variable reference in the pattern itemm. */ $2->patternItem->varRef = $1->varRef; if ( $1->varRef != 0 ) { if ( pd->curLocalFrame->checkRedecl( $1->varRef->name ) != 0 ) { error( $1->varRef->loc ) << "variable " << $1->varRef->name << " redeclared" << endp; } TypeRef *typeRef = $2->patternItem->factor->typeRef; ObjField *objField = new ObjField( InputLoc(), typeRef, $1->varRef->name ); /* Insert it into the field map. */ pd->curLocalFrame->insertField( $1->varRef->name, objField ); } }; pattern_el: '"' litpat_el_list '"'; pattern_el: '?' TK_Word final { /* FIXME: Implement */ assert(false); }; nonterm pattern_el_type_or_lit { PatternItem *patternItem; }; pattern_el_type_or_lit: region_qual TK_Word opt_repeat final { TypeRef *typeRef = TypeRef::cons( $2->loc, $1->nspaceQual, $2->data ); typeRef->repeatType = $3->repeatType; ProdEl *factor = new ProdEl( ProdEl::ReferenceType, $2->loc, 0, false, typeRef, 0 ); $$->patternItem = PatternItem::cons( $2->loc, factor, PatternItem::FactorType ); patternItemList->append( $$->patternItem ); }; pattern_el_type_or_lit: region_qual TK_Literal opt_repeat final { PdaLiteral *literal = new PdaLiteral( $2->loc, *$2 ); TypeRef *typeRef = TypeRef::cons( $2->loc, $1->nspaceQual, literal ); typeRef->repeatType = $3->repeatType; ProdEl *factor = new ProdEl( ProdEl::ReferenceType, $2->loc, 0, false, typeRef, 0 ); $$->patternItem = PatternItem::cons( $2->loc, factor, PatternItem::FactorType ); patternItemList->append( $$->patternItem ); }; nonterm opt_label { /* Variable reference. */ LangVarRef *varRef; }; opt_label: TK_Word ':' final { $$->varRef = new LangVarRef( $1->loc, new QualItemVect, $1->data ); }; opt_label: final { $$->varRef = 0; }; # # Replacement # repl_list: repl_list replacement; repl_list: init_repl_list replacement; init_repl_list: final { replItemList = new ReplItemList; }; replacement: '"' lit_repl_el_list '"'; replacement: '[' repl_el_list ']'; lit_repl_el_list: lit_repl_el_list lit_repl_el; lit_repl_el_list: ; lit_repl_el: TK_LitPat final { ReplItem *replItem = ReplItem::cons( $1->loc, ReplItem::InputText, $1->data ); replItemList->append( replItem ); }; lit_repl_el: '[' repl_el_list ']'; repl_el_list: repl_el_list repl_el; repl_el_list: ; repl_el: region_qual TK_Literal final { PdaLiteral *literal = new PdaLiteral( $2->loc, *$2 ); TypeRef *typeRef = TypeRef::cons( $2->loc, $1->nspaceQual, literal ); typeRef->repeatType = RepeatNone; ProdEl *factor = new ProdEl( ProdEl::LiteralType, $2->loc, 0, false, typeRef, 0 ); ReplItem *replItem = ReplItem::cons( $2->loc, ReplItem::FactorType, factor ); replItemList->append( replItem ); }; repl_el: '"' lit_repl_el_list '"'; repl_el: code_expr final { ReplItem *replItem = ReplItem::cons( $1->expr->loc, ReplItem::ExprType, $1->expr ); replItemList->append( replItem ); }; # # Accum # accumulate: init_repl_list accum_list; #accumulate: init_repl_list code_expr # final { # ReplItem *replItem = ReplItem::cons( $2->expr->loc, ReplItem::ExprType, $2->expr ); # replItemList->append( replItem ); # }; accum_list: accum_list accum; accum_list: accum; init_accum_list: final { replItemList = new ReplItemList; }; accum: '"' lit_accum_el_list '"'; accum: '[' accum_el_list ']'; lit_accum_el_list: lit_accum_el_list lit_accum_el; lit_accum_el_list: ; lit_accum_el: TK_LitPat final { ReplItem *replItem = ReplItem::cons( $1->loc, ReplItem::InputText, $1->data ); replItemList->append( replItem ); }; lit_accum_el: '[' accum_el_list ']'; accum_el_list: accum_el_list accum_el; accum_el_list: ; #accum_el: region_qual TK_Literal # final { # PdaLiteral *literal = new PdaLiteral( $2->loc, *$2 ); # ProdEl *factor = new ProdEl( $2->loc, false, $1->nspaceQual, # literal, 0 ); # ReplItem *replItem = new ReplItem( $2->loc, ReplItem::FactorType, factor ); # replItemList->append( replItem ); # }; accum_el: code_expr final { ReplItem *replItem = ReplItem::cons( $1->expr->loc, ReplItem::ExprType, $1->expr ); replItemList->append( replItem ); }; accum_el: '"' lit_accum_el_list '"'; # # String # string_list: string_list string; string_list: init_string_list string; init_string_list: final { replItemList = new ReplItemList; }; string: '"' lit_string_el_list '"'; string: '[' string_el_list ']'; lit_string_el_list: lit_string_el_list lit_string_el; lit_string_el_list: ; lit_string_el: TK_LitPat final { ReplItem *replItem = ReplItem::cons( $1->loc, ReplItem::InputText, $1->data ); replItemList->append( replItem ); }; lit_string_el: '[' string_el_list ']'; string_el_list: string_el_list string_el; string_el_list: ; #accum_el: region_qual TK_Literal # final { # PdaLiteral *literal = new PdaLiteral( $2->loc, *$2 ); # ProdEl *factor = new ProdEl( $2->loc, false, $1->nspaceQual, # literal, 0 ); # ReplItem *replItem = new ReplItem( $2->loc, ReplItem::FactorType, factor ); # replItemList->append( replItem ); # }; string_el: code_expr final { ReplItem *replItem = ReplItem::cons( $1->expr->loc, ReplItem::ExprType, $1->expr ); replItemList->append( replItem ); }; string_el: '"' lit_string_el_list '"'; prod_el_list: prod_el_list prod_el final { curProdElList->append( $2->factor ); }; prod_el_list: final { curProdElList = new ProdElList; }; nonterm opt_no_ignore { bool value; }; opt_no_ignore: KW_Ni final { $$->value = true; }; opt_no_ignore: final { $$->value = false; }; nonterm prod_el { ProdEl *factor; }; prod_el: opt_capture opt_commit region_qual TK_Word opt_repeat final { TypeRef *typeRef = TypeRef::cons( $4->loc, $3->nspaceQual, $4->data ); typeRef->repeatType = $5->repeatType; $$->factor = new ProdEl( ProdEl::ReferenceType, $4->loc, $1->objField, $2->commit, typeRef, 0 ); /* If there is a capture, create the field. */ if ( $1->objField != 0 ) { /* Might already exist. */ ObjField *objField = pd->objectDef->checkRedecl( $1->objField->name ); if ( objField == 0 ) { objField = $1->objField; objField->typeRef = typeRef; pd->objectDef->insertField( objField->name, objField ); } else { /* FIXME: check the types are the same. */ //error() << "object field renamed" << endp; } objField->isRhsGet = true; RhsVal rhsVal( curDefList->length(), curProdElList->length() ); objField->rhsVal.append( RhsVal( curDefList->length(), curProdElList->length() ) ); } }; prod_el: opt_capture opt_commit region_qual TK_Literal opt_repeat final { /* Create a new factor node going to a concat literal. */ PdaLiteral *literal = new PdaLiteral( $4->loc, *$4 ); TypeRef *typeRef = TypeRef::cons( $4->loc, $3->nspaceQual, literal ); typeRef->repeatType = $5->repeatType; $$->factor = new ProdEl( ProdEl::LiteralType, $4->loc, $1->objField, $2->commit, typeRef, 0 ); /* If there is a capture, create the field. */ if ( $1->objField != 0 ) { $1->objField->typeRef = typeRef; if ( pd->objectDef->checkRedecl( $1->objField->name ) != 0 ) error() << "object field renamed" << endp; pd->objectDef->insertField( $1->objField->name, $1->objField ); } }; nonterm opt_repeat { bool opt; bool repeat; RepeatType repeatType; }; opt_repeat: '*' final { $$->opt = false; $$->repeat = true; $$->repeatType = RepeatRepeat; }; opt_repeat: '+' final { $$->opt = false; $$->repeat = false; $$->repeatType = RepeatList; }; opt_repeat: '?' final { $$->opt = true; $$->repeat = false; $$->repeatType = RepeatOpt; }; opt_repeat: final { $$->opt = false; $$->repeat = false; $$->repeatType = RepeatNone; }; nonterm region_qual { NamespaceQual *nspaceQual; }; region_qual: region_qual TK_Word TK_DoubleColon final { $$->nspaceQual = $1->nspaceQual; $$->nspaceQual->qualNames.append( $2->data ); }; region_qual: final { $$->nspaceQual = new NamespaceQual( namespaceStack.top(), regionStack.top() ); }; literal_def: KW_Literal literal_list; literal_list: literal_list ',' literal_item; literal_list: literal_item; literal_item: opt_no_ignore TK_Literal opt_no_ignore final { /* Create a name for the literal. */ String name( 32, "_literal_%.4x", pd->nextTokenId ); bool insideRegion = regionStack.top() != pd->rootRegion; if ( !insideRegion ) { /* Just for ignores. */ String scannerNameIgn( name.length() + 2, "<%s>-ign", name.data ); TokenRegion *tokenRegionIgn = createRegion( scannerNameIgn ); /* Just for collect ignores. Will use the ignore-only start state. */ String scannerNameCi( name.length() + 2, "<%s>-ci", name.data ); TokenRegion *tokenRegionCi = createRegion( scannerNameCi ); /* Just for tokens. */ String scannerNameTok( name.length() + 2, "<%s>-tok", name.data ); TokenRegion *tokenRegionTok = createRegion( scannerNameTok ); /* Make a new token region just for the token. */ String scannerName( name.length() + 2, "<%s>", name.data ); TokenRegion *tokenRegion = createRegion( scannerName ); regionStack.push( tokenRegion ); tokenRegion->ignoreOnlyRegion = tokenRegionIgn; tokenRegion->tokenOnlyRegion = tokenRegionTok; tokenRegion->ciRegion = tokenRegionCi; tokenRegion->isFullRegion = true; tokenRegionIgn->isIgnoreOnly = true; tokenRegionCi->isCiOnly = true; tokenRegionTok->isTokenOnly = true; tokenRegionIgn->derivedFrom = tokenRegion; tokenRegionCi->derivedFrom = tokenRegion; tokenRegionTok->derivedFrom = tokenRegion; } bool unusedCI; String interp; prepareLitString( interp, unusedCI, $2->data, $2->loc ); /* Look for the production's associated region. */ Namespace *nspace = namespaceStack.top(); TokenRegion *region = regionStack.top(); LiteralDictEl *ldel = nspace->literalDict.find( interp ); if ( ldel != 0 ) error( $2->loc ) << "literal already defined in this namespace" << endp; else { Join *join = new Join( Expression::cons( Term::cons( FactorWithAug::cons( FactorWithRep::cons( $2->loc, FactorWithNeg::cons( $2->loc, Factor::cons( Literal::cons( $2->loc, $2->data, Literal::LitString ) ) ) ) ) ) ) ); if ( strcmp( interp.data, "" ) == 0 ) { TokenDef *tokenDef = new TokenDef( name, $2->data, true, false, join, 0, $2->loc, pd->nextTokenId++, nspace, region, 0, 0, 0 ); //region->tokenDefList.append( tokenDef ); ldel = nspace->literalDict.insert( interp, tokenDef ); nspace->tokenDefList.append( tokenDef ); tokenDef->isZero = true; } else { TokenDef *tokenDef = new TokenDef( name, $2->data, true, false, join, 0, $2->loc, pd->nextTokenId++, nspace, region, 0, 0, 0 ); region->tokenDefList.append( tokenDef ); ldel = nspace->literalDict.insert( interp, tokenDef ); nspace->tokenDefList.append( tokenDef ); if ( $1->value ) tokenDef->noPreIgnore = true; if ( $3->value ) tokenDef->noPostIgnore = true; TokenDef *tokenDefTok = new TokenDef( name + "_tok", $2->data, true, false, join, 0, $2->loc, pd->nextTokenId++, nspace, region->tokenOnlyRegion, 0, 0, 0 ); tokenDefTok->dupOf = tokenDef; region->tokenOnlyRegion->tokenDefList.append( tokenDefTok ); ldel = nspace->literalDict.insert( "|" + interp + "_tok", tokenDefTok ); nspace->tokenDefList.append( tokenDefTok ); } } if ( !insideRegion ) { /* Leave the region just for this token. */ regionStack.pop(); } }; # These two productions are responsible for setting and unsetting the Regular # language scanning context. enter_rl: try { enterRl = true; } undo { enterRl = false; }; leave_rl: try { enterRl = false; } undo { enterRl = true; }; token_def: token_or_ignore token_def_name obj_var_list enter_rl opt_no_ignore '/' opt_rl_join leave_rl '/' opt_no_ignore opt_translate final { bool ignore = $1->ignore; String name = $2->name; Join *join = $7->join; CodeBlock *transBlock = $11->transBlock; /* Check the region if this is for an ignore. */ if ( ignore && !pd->insideRegion ) error($1->loc) << "ignore tokens can only appear inside scanners" << endp; /* Check the name if this is a token. */ if ( !ignore && name == 0 ) error($1->loc) << "tokens must have a name" << endp; /* Give a default name to ignores. */ if ( name == 0 ) name.setAs( 32, "_ignore_%.4x", pd->nextTokenId ); Namespace *nspace = namespaceStack.top(); TokenRegion *region = regionStack.top(); TokenDef *tokenDef = new TokenDef( name, String(), false, ignore, join, transBlock, $1->loc, pd->nextTokenId++, nspace, region, &reCaptureVect, pd->objectDef, contextStack.length() > 0 ? contextStack.top() : 0 ); region->tokenDefList.append( tokenDef ); nspace->tokenDefList.append( tokenDef ); if ( $5->value ) tokenDef->noPreIgnore = true; if ( $10->value ) tokenDef->noPostIgnore = true; /* All again for the ignore. */ if ( ignore ) { TokenDef *tokenDefIgn = new TokenDef( name + "_ign", String(), false, ignore, join, 0, $1->loc, pd->nextTokenId++, nspace, region->ignoreOnlyRegion, &reCaptureVect, pd->objectDef, contextStack.length() > 0 ? contextStack.top() : 0 ); tokenDefIgn->dupOf = tokenDef; region->ignoreOnlyRegion->tokenDefList.append( tokenDefIgn ); nspace->tokenDefList.append( tokenDefIgn ); } else { TokenDef *tokenDefTok = new TokenDef( name + "_tok", String(), false, ignore, join, 0, $1->loc, pd->nextTokenId++, nspace, region->tokenOnlyRegion, &reCaptureVect, pd->objectDef, contextStack.length() > 0 ? contextStack.top() : 0 ); tokenDefTok->dupOf = tokenDef; region->tokenOnlyRegion->tokenDefList.append( tokenDefTok ); nspace->tokenDefList.append( tokenDefTok ); } /* This is created and pushed in the name. */ if ( !pd->insideRegion ) { /* Leave the region that we made just for this token. */ regionStack.pop(); } if ( join != 0 ) { /* Create a regular language definition so the token can be used to * make other tokens */ addRegularDef( $1->loc, namespaceStack.top(), name, join ); } reCaptureVect.empty(); }; nonterm token_or_ignore { InputLoc loc; bool ignore; }; token_or_ignore: KW_Token final { $$->loc = $1->loc; $$->ignore = false; }; token_or_ignore: KW_Ignore final { $$->loc = $1->loc; $$->ignore = true; }; nonterm class token_def_name { String name; }; token_def_name: opt_name final { String name = $1->name; $$->name = name; pd->insideRegion = regionStack.top() != pd->rootRegion; curDefineId = name; if ( !pd->insideRegion ) { /* For just ignores. */ String scannerNameIgn( name.length() + 2, "<%s>-ign", name.data ); TokenRegion *tokenRegionIgn = createRegion( scannerNameIgn ); /* Just for explicitly collecting ignores. */ String scannerNameCi( name.length() + 2, "<%s>-ci", name.data ); TokenRegion *tokenRegionCi = createRegion( scannerNameCi ); /* Just for tokens. */ String scannerNameTok( name.length() + 2, "<%s>-tok", name.data ); TokenRegion *tokenRegionTok = createRegion( scannerNameTok ); /* If not inside a region, make one for the token. */ String scannerName( name.length() + 2, "<%s>", name.data ); TokenRegion *tokenRegion = createRegion( scannerName ); regionStack.push( tokenRegion ); tokenRegion->ignoreOnlyRegion = tokenRegionIgn; tokenRegion->tokenOnlyRegion = tokenRegionTok; tokenRegion->ciRegion = tokenRegionCi; tokenRegion->isFullRegion = true; tokenRegionIgn->isIgnoreOnly = true; tokenRegionCi->isCiOnly = true; tokenRegionTok->isTokenOnly = true; tokenRegionIgn->derivedFrom = tokenRegion; tokenRegionCi->derivedFrom = tokenRegion; tokenRegionTok->derivedFrom = tokenRegion; } /* Reset the lable id counter. */ pd->nextLabelId = 0; }; nonterm class opt_name { String name; }; opt_name: TK_Word final { $$->name = $1->data; }; opt_name: ; nonterm opt_translate { CodeBlock *transBlock; }; opt_translate: block_open lang_stmt_list block_close final { $$->transBlock = new CodeBlock( $2->stmtList ); $$->transBlock->localFrame = $1->localFrame; $$->transBlock->context = contextStack.length() == 0 ? 0 : contextStack.top(); }; opt_translate: final { $$->transBlock = 0; }; pre_eof: KW_Preeof block_open lang_stmt_list block_close final { bool insideRegion = regionStack.top() != pd->rootRegion; if ( !insideRegion ) error($1->loc) << "preeof must be used inside an existing region" << endl; CodeBlock *codeBlock = new CodeBlock( $3->stmtList ); codeBlock->localFrame = $2->localFrame; codeBlock->context = contextStack.length() == 0 ? 0 : contextStack.top(); TokenRegion *region = regionStack.top(); region->preEofBlock = codeBlock; }; rl_def: KW_Rl machine_name enter_rl '/' rl_join leave_rl '/' final { /* Generic creation of machine for instantiation and assignment. */ addRegularDef( $2->loc, namespaceStack.top(), $2->data, $5->join ); if ( reCaptureVect.length() > 0 ) error($1->loc) << "rl definitions cannot capture vars" << endl; }; type class token_data { InputLoc loc; String data; }; nonterm machine_name uses token_data; machine_name: TK_Word final { /* Make/get the priority key. The name may have already been referenced * and therefore exist. */ PriorDictEl *priorDictEl; if ( pd->priorDict.insert( $1->data, pd->nextPriorKey, &priorDictEl ) ) pd->nextPriorKey += 1; pd->curDefPriorKey = priorDictEl->value; /* Make/get the local error key. */ LocalErrDictEl *localErrDictEl; if ( pd->localErrDict.insert( $1->data, pd->nextLocalErrKey, &localErrDictEl ) ) pd->nextLocalErrKey += 1; pd->curDefLocalErrKey = localErrDictEl->value; $$->loc = $1->loc; $$->data = $1->data; }; # # Reduce statements # nonterm opt_reduce_code { CodeBlock *codeBlock; }; opt_reduce_code: final { $$->codeBlock = 0; }; opt_reduce_code: start_reduce lang_stmt_list block_close final { $$->codeBlock = new CodeBlock( $2->stmtList ); $$->codeBlock->localFrame = $1->localFrame; $$->codeBlock->context = contextStack.length() == 0 ? 0 : contextStack.top(); }; nonterm start_reduce uses block_open; start_reduce: block_open final { $$->localFrame = $1->localFrame; }; nonterm lang_stmt_list { StmtList *stmtList; }; lang_stmt_list: rec_stmt_list opt_require_stmt final { $$->stmtList = $1->stmtList; if ( $2->stmt != 0 ) $$->stmtList->append( $2->stmt ); }; nonterm rec_stmt_list uses lang_stmt_list; rec_stmt_list: rec_stmt_list statement final { $$->stmtList = $1->stmtList; /* Maybe a statement was generated. */ if ( $2->stmt != 0 ) $$->stmtList->append( $2->stmt ); }; rec_stmt_list: final { $$->stmtList = new StmtList; }; nonterm opt_def_init { LangExpr *expr; LangStmt::Type assignType; }; opt_def_init: '=' code_expr final { $$->expr = $2->expr; $$->assignType = LangStmt::AssignType; }; opt_def_init: final { $$->expr = 0; }; scope_push: final { pd->curLocalFrame->pushScope(); //cout << "push scope" << endl; }; scope_pop: final { pd->curLocalFrame->popScope(); //cout << "pop scope" << endl; }; nonterm statement { LangStmt *stmt; }; nonterm for_scope uses statement; statement: var_def opt_def_init final { /* By default no statement here. Maybe will add an initialization. */ $$->stmt = 0; /* Check for redeclaration. */ if ( pd->curLocalFrame->checkRedecl( $1->objField->name ) != 0 ) { error( $1->objField->loc ) << "variable " << $1->objField->name << " redeclared" << endp; } /* Insert it into the field map. */ pd->curLocalFrame->insertField( $1->objField->name, $1->objField ); //cout << "var def " << $1->objField->name << endl; if ( $2->expr != 0 ) { LangVarRef *varRef = new LangVarRef( $1->objField->loc, new QualItemVect, $1->objField->name ); $$->stmt = LangStmt::cons( $1->objField->loc, $2->assignType, varRef, $2->expr ); } }; statement: var_ref '=' code_expr final { $$->stmt = LangStmt::cons( $2->loc, LangStmt::AssignType, $1->varRef, $3->expr ); }; statement: KW_Print '(' code_expr_list ')' final { $$->stmt = LangStmt::cons( $1->loc, LangStmt::PrintType, $3->exprVect ); }; statement: KW_PrintXMLAC '(' code_expr_list ')' final { $$->stmt = LangStmt::cons( $1->loc, LangStmt::PrintXMLACType, $3->exprVect ); }; statement: KW_PrintXML '(' code_expr_list ')' final { $$->stmt = LangStmt::cons( $1->loc, LangStmt::PrintXMLType, $3->exprVect ); }; statement: KW_PrintStream '(' code_expr_list ')' final { $$->stmt = LangStmt::cons( $1->loc, LangStmt::PrintStreamType, $3->exprVect ); }; statement: code_expr final { $$->stmt = LangStmt::cons( InputLoc(), LangStmt::ExprType, $1->expr ); }; statement: if_stmt final { $$->stmt = $1->stmt; }; statement: KW_Reject final { $$->stmt = LangStmt::cons( $1->loc, LangStmt::RejectType ); }; statement: KW_While scope_push code_expr block_or_single scope_pop final { $$->stmt = LangStmt::cons( LangStmt::WhileType, $3->expr, $4->stmtList ); }; for_scope: TK_Word ':' type_ref KW_In iter_call block_or_single final { /* Check for redeclaration. */ if ( pd->curLocalFrame->checkRedecl( $1->data ) != 0 ) error( $1->loc ) << "variable " << $1->data << " redeclared" << endp; /* Note that we pass in a null type reference. This type is dependent * on the result of the iter_call lookup since it must contain a reference * to the iterator that is called. This lookup is done at compile time. */ ObjField *iterField = new ObjField( $1->loc, (TypeRef*)0, $1->data ); pd->curLocalFrame->insertField( $1->data, iterField ); $$->stmt = LangStmt::cons( $1->loc, LangStmt::ForIterType, iterField, $3->typeRef, $5->langTerm, $6->stmtList ); }; statement: KW_For scope_push for_scope scope_pop final { $$->stmt = $3->stmt; }; statement: KW_Return code_expr final { $$->stmt = LangStmt::cons( $1->loc, LangStmt::ReturnType, $2->expr ); }; statement: KW_Break final { $$->stmt = LangStmt::cons( LangStmt::BreakType ); }; statement: KW_Yield var_ref final { $$->stmt = LangStmt::cons( LangStmt::YieldType, $2->varRef ); }; nonterm opt_require_stmt uses statement; opt_require_stmt: scope_push require_pattern lang_stmt_list scope_pop final { $$->stmt = LangStmt::cons( LangStmt::IfType, $2->expr, $3->stmtList, 0 ); }; opt_require_stmt: final { $$->stmt = 0; }; nonterm require_pattern uses code_expr; require_pattern: KW_Require var_ref pattern_list final { Namespace *nspace = namespaceStack.top(); TokenRegion *region = regionStack.top(); Pattern *pattern = Pattern::cons( $1->loc, nspace, region, patternItemList, pd->nextPatReplId++ ); pd->patternList.append( pattern ); $$->expr = LangExpr::cons( LangTerm::cons( LangTerm::MatchType, $2->varRef, pattern ) ); }; nonterm block_or_single uses lang_stmt_list; block_or_single: '{' lang_stmt_list '}' final { $$->stmtList = $2->stmtList; }; block_or_single: statement final { $$->stmtList = new StmtList; $$->stmtList->append( $1->stmt ); }; nonterm iter_call { LangTerm *langTerm; }; iter_call: var_ref '(' opt_code_expr_list ')' final { $$->langTerm = LangTerm::cons( $1->varRef, $3->exprVect ); }; iter_call: TK_Word final { $$->langTerm = LangTerm::cons( LangTerm::VarRefType, new LangVarRef( $1->loc, new QualItemVect, $1->data ) ); }; # # If Statements # nonterm if_stmt uses statement; if_stmt: KW_If scope_push code_expr block_or_single scope_pop elsif_list final { $$->stmt = LangStmt::cons( LangStmt::IfType, $3->expr, $4->stmtList, $6->stmt ); }; nonterm elsif_list { LangStmt *stmt; }; elsif_list: elsif_clause elsif_list final { /* Put any of the followng elseif part, an else, or null into the elsePart. */ $$->stmt = $1->stmt; $$->stmt->elsePart = $2->stmt; }; elsif_list: optional_else final { $$->stmt = $1->stmt; }; nonterm elsif_clause { LangStmt *stmt; }; elsif_clause: KW_Elsif scope_push code_expr block_or_single scope_pop final { $$->stmt = LangStmt::cons( LangStmt::IfType, $3->expr, $4->stmtList, 0 ); }; nonterm optional_else { LangStmt *stmt; }; optional_else: KW_Else scope_push block_or_single scope_pop final { $$->stmt = LangStmt::cons( LangStmt::ElseType, $3->stmtList ); }; optional_else: final { $$->stmt = 0; }; # # Code Expression Lists. # nonterm code_expr_list { ExprVect *exprVect; }; code_expr_list: code_expr_list code_expr final { $$->exprVect = $1->exprVect; $$->exprVect->append( $2->expr ); }; code_expr_list: code_expr final { $$->exprVect = new ExprVect; $$->exprVect->append( $1->expr ); }; nonterm opt_code_expr_list uses code_expr_list; opt_code_expr_list: code_expr_list final { $$->exprVect = $1->exprVect; }; opt_code_expr_list: final { $$->exprVect = 0; }; # # Type list # nonterm type_list { TypeRefVect *typeRefVect; }; type_list: type_list ',' type_ref final { $$->typeRefVect = $1->typeRefVect; $$->typeRefVect->append( $3->typeRef ); }; type_list: type_ref final { $$->typeRefVect = new TypeRefVect; $$->typeRefVect->append( $1->typeRef ); }; nonterm opt_type_list uses type_list; opt_type_list: type_list final { $$->typeRefVect = $1->typeRefVect; }; opt_type_list: final { $$->typeRefVect = 0; }; # # Variable reference # nonterm var_ref { LangVarRef *varRef; }; var_ref: qual TK_Word final { $$->varRef = new LangVarRef( $2->loc, $1->qual, $2->data ); }; nonterm qual { QualItemVect *qual; }; qual: qual TK_Word '.' final { $$->qual = $1->qual; $$->qual->append( QualItem( $2->loc, $2->data, QualItem::Dot ) ); }; qual: qual TK_Word TK_RightArrow final { $$->qual = $1->qual; $$->qual->append( QualItem( $2->loc, $2->data, QualItem::Arrow ) ); }; qual: final { $$->qual = new QualItemVect; }; # # Code expression # nonterm code_expr { LangExpr *expr; }; code_expr: code_expr TK_AmpAmp code_relational final { $$->expr = LangExpr::cons( $2->loc, $1->expr, OP_LogicalAnd, $3->expr ); }; code_expr: code_expr TK_BarBar code_relational final { $$->expr = LangExpr::cons( $2->loc, $1->expr, OP_LogicalOr, $3->expr ); }; code_expr: code_relational final { $$->expr = $1->expr; }; nonterm code_relational uses code_expr; code_relational: code_relational TK_DoubleEql code_additive final { $$->expr = LangExpr::cons( $2->loc, $1->expr, OP_DoubleEql, $3->expr ); }; code_relational: code_relational TK_NotEql code_additive final { $$->expr = LangExpr::cons( $2->loc, $1->expr, OP_NotEql, $3->expr ); }; code_relational: code_relational '<' code_additive final { $$->expr = LangExpr::cons( $2->loc, $1->expr, '<', $3->expr ); }; code_relational: code_relational '>' code_additive final { $$->expr = LangExpr::cons( $2->loc, $1->expr, '>', $3->expr ); }; code_relational: code_relational TK_LessEql code_additive final { $$->expr = LangExpr::cons( $2->loc, $1->expr, OP_LessEql, $3->expr ); }; code_relational: code_relational TK_GrtrEql code_additive final { $$->expr = LangExpr::cons( $2->loc, $1->expr, OP_GrtrEql, $3->expr ); }; code_relational: code_additive final { $$->expr = $1->expr; }; nonterm code_additive uses code_expr; code_additive: code_additive '+' code_multiplicitive final { $$->expr = LangExpr::cons( $2->loc, $1->expr, '+', $3->expr ); }; code_additive: code_additive '-' code_multiplicitive final { $$->expr = LangExpr::cons( $2->loc, $1->expr, '-', $3->expr ); }; code_additive: code_multiplicitive final { $$->expr = $1->expr; }; nonterm code_multiplicitive uses code_expr; code_multiplicitive: code_multiplicitive '*' code_unary final { $$->expr = LangExpr::cons( $2->loc, $1->expr, '*', $3->expr ); }; code_multiplicitive: code_multiplicitive '/' code_unary final { $$->expr = LangExpr::cons( $2->loc, $1->expr, '/', $3->expr ); }; code_multiplicitive: code_unary final { $$->expr = $1->expr; }; nonterm code_unary uses code_expr; code_unary: '!' code_factor final { $$->expr = LangExpr::cons( $1->loc, '!', $2->expr ); }; code_unary: '$' code_factor final { $$->expr = LangExpr::cons( $1->loc, '$', $2->expr ); }; code_unary: '^' code_factor final { $$->expr = LangExpr::cons( $1->loc, '^', $2->expr ); }; code_unary: '%' code_factor final { $$->expr = LangExpr::cons( $1->loc, '%', $2->expr ); }; code_unary: code_factor final { $$->expr = $1->expr; }; nonterm opt_capture uses var_def; opt_capture: TK_Word ':' final { $$->objField = new ObjField( $1->loc, 0, $1->data ); }; opt_capture: final { $$->objField = 0; }; nonterm code_factor uses code_expr; code_factor: TK_Number final { $$->expr = LangExpr::cons( LangTerm::cons( LangTerm::NumberType, $1->data ) ); }; code_factor: TK_Literal final { $$->expr = LangExpr::cons( LangTerm::cons( LangTerm::StringType, $1->data ) ); }; code_factor: var_ref '(' opt_code_expr_list ')' final { $$->expr = LangExpr::cons( LangTerm::cons( $1->varRef, $3->exprVect ) ); }; code_factor: var_ref final { $$->expr = LangExpr::cons( LangTerm::cons( LangTerm::VarRefType, $1->varRef ) ); }; code_factor: KW_Match var_ref pattern_list final { Namespace *nspace = namespaceStack.top(); TokenRegion *region = regionStack.top(); Pattern *pattern = Pattern::cons( $1->loc, nspace, region, patternItemList, pd->nextPatReplId++ ); pd->patternList.append( pattern ); $$->expr = LangExpr::cons( LangTerm::cons( LangTerm::MatchType, $2->varRef, pattern ) ); }; code_factor: KW_New code_factor final { $$->expr = LangExpr::cons( LangTerm::cons( LangTerm::NewType, $2->expr ) ); }; code_factor: KW_Construct opt_capture type_ref opt_field_init repl_list final { Namespace *nspace = namespaceStack.top(); TokenRegion *region = regionStack.top(); Replacement *replacement = Replacement::cons( $1->loc, nspace, region, replItemList, pd->nextPatReplId++ ); pd->replList.append( replacement ); LangVarRef *varRef = 0; if ( $2->objField != 0 ) varRef = new LangVarRef( $2->objField->loc, new QualItemVect, $2->objField->name ); $$->expr = LangExpr::cons( LangTerm::cons( $1->loc, LangTerm::ConstructType, varRef, $2->objField, $3->typeRef, $4->fieldInitVect, replacement ) ); /* Check for redeclaration. */ if ( $2->objField != 0 ) { if ( pd->curLocalFrame->checkRedecl( $2->objField->name ) != 0 ) { error( $2->objField->loc ) << "variable " << $2->objField->name << " redeclared" << endp; } /* Insert it into the field map. */ $2->objField->typeRef = $3->typeRef; pd->curLocalFrame->insertField( $2->objField->name, $2->objField ); } }; code_factor: KW_Parse opt_capture type_ref opt_field_init accumulate final { Namespace *nspace = namespaceStack.top(); TokenRegion *region = regionStack.top(); ReplItemList *emptyReplItemList = new ReplItemList; Replacement *replacement = Replacement::cons( $1->loc, nspace, region, emptyReplItemList, pd->nextPatReplId++ ); pd->replList.append( replacement ); LangVarRef *varRef = 0; if ( $2->objField != 0 ) varRef = new LangVarRef( $2->objField->loc, new QualItemVect, $2->objField->name ); NamespaceQual *nspaceQual = new NamespaceQual( namespaceStack.top(), regionStack.top() ); TypeRef *parserTypeRef = TypeRef::cons( TypeRef::Parser, InputLoc(), nspaceQual, $3->typeRef, 0 ); ParserText *parserText = ParserText::cons( $2->loc, nspace, region, replItemList ); pd->parserTextList.append( parserText ); $$->expr = LangExpr::cons( LangTerm::cons( $1->loc, LangTerm::Parse2Type, varRef, $2->objField, parserTypeRef, $4->fieldInitVect, replacement, parserText ) ); /* Check for redeclaration. */ if ( $2->objField != 0 ) { if ( pd->curLocalFrame->checkRedecl( $2->objField->name ) != 0 ) { error( $2->objField->loc ) << "variable " << $2->objField->name << " redeclared" << endp; } /* Insert it into the field map. */ $2->objField->typeRef = parserTypeRef; pd->curLocalFrame->insertField( $2->objField->name, $2->objField ); } }; code_factor: KW_Parse opt_capture type_ref '(' opt_code_expr_list ')' final { String parserName = $3->typeRef->typeName + "_parser"; /* Get the language element. */ Namespace *nspace = namespaceStack.top(); GenericType *generic = 0; NamespaceQual *nspaceQual = new NamespaceQual( namespaceStack.top(), regionStack.top() ); TypeRef *parserTypeRef = TypeRef::cons( TypeRef::Parser, InputLoc(), nspaceQual, $3->typeRef, 0 ); Replacement *replacement = Replacement::cons( $1->loc, nspace, pd->rootRegion, new ReplItemList, pd->nextPatReplId++ ); pd->replList.append( replacement ); LangVarRef *varRef = 0; if ( $2->objField != 0 ) varRef = new LangVarRef( $2->objField->loc, new QualItemVect, $2->objField->name ); $$->expr = LangExpr::cons( LangTerm::cons( $1->loc, LangTerm::OrigParseType, varRef, $2->objField, $3->typeRef, generic, parserTypeRef, replacement ) ); $$->expr->term->args = $5->exprVect; /* Check for redeclaration. */ if ( $2->objField != 0 ) { if ( pd->curLocalFrame->checkRedecl( $2->objField->name ) != 0 ) { error( $2->objField->loc ) << "variable " << $2->objField->name << " redeclared" << endp; } /* Insert it into the field map. */ $2->objField->typeRef = $3->typeRef; pd->curLocalFrame->insertField( $2->objField->name, $2->objField ); } }; code_factor: KW_ParseStop opt_capture type_ref '(' opt_code_expr_list ')' final { /* This is a silly clone. To be fixed later. */ String parserName = $3->typeRef->typeName + "_parser"; /* Get the language element. */ Namespace *nspace = namespaceStack.top(); GenericType *generic = 0; NamespaceQual *nspaceQual = new NamespaceQual( namespaceStack.top(), regionStack.top() ); TypeRef *parserTypeRef = TypeRef::cons( TypeRef::Parser, InputLoc(), nspaceQual, $3->typeRef, 0 ); Replacement *replacement = Replacement::cons( $1->loc, nspace, pd->rootRegion, new ReplItemList, pd->nextPatReplId++ ); pd->replList.append( replacement ); LangVarRef *varRef = 0; if ( $2->objField != 0 ) varRef = new LangVarRef( $2->objField->loc, new QualItemVect, $2->objField->name ); $$->expr = LangExpr::cons( LangTerm::cons( $1->loc, LangTerm::OrigParseStopType, varRef, $2->objField, $3->typeRef, generic, parserTypeRef, replacement ) ); $$->expr->term->args = $5->exprVect; /* Check for redeclaration. */ if ( $2->objField != 0 ) { if ( pd->curLocalFrame->checkRedecl( $2->objField->name ) != 0 ) { error( $2->objField->loc ) << "variable " << $2->objField->name << " redeclared" << endp; } /* Insert it into the field map. */ $2->objField->typeRef = $3->typeRef; pd->curLocalFrame->insertField( $2->objField->name, $2->objField ); } }; code_factor: var_ref TK_LtLt accumulate final { Namespace *nspace = namespaceStack.top(); TokenRegion *region = regionStack.top(); ParserText *parserText = ParserText::cons( $2->loc, nspace, region, replItemList ); pd->parserTextList.append( parserText ); $$->expr = LangExpr::cons( LangTerm::cons( LangTerm::SendType, $1->varRef, parserText ) ); }; code_factor: KW_Send var_ref accumulate final { Namespace *nspace = namespaceStack.top(); TokenRegion *region = regionStack.top(); ParserText *parserText = ParserText::cons( $1->loc, nspace, region, replItemList ); pd->parserTextList.append( parserText ); $$->expr = LangExpr::cons( LangTerm::cons( LangTerm::SendType, $2->varRef, parserText ) ); }; code_factor: KW_TypeId '<' type_ref '>' final { $$->expr = LangExpr::cons( LangTerm::cons( $1->loc, LangTerm::TypeIdType, $3->typeRef ) ); }; code_factor: type_ref KW_In var_ref final { $$->expr = LangExpr::cons( LangTerm::cons( $2->loc, LangTerm::SearchType, $1->typeRef, $3->varRef ) ); }; code_factor: KW_Nil final { $$->expr = LangExpr::cons( LangTerm::cons( $1->loc, LangTerm::NilType ) ); }; code_factor: KW_True final { $$->expr = LangExpr::cons( LangTerm::cons( $1->loc, LangTerm::TrueType ) ); }; code_factor: KW_False final { $$->expr = LangExpr::cons( LangTerm::cons( $1->loc, LangTerm::FalseType ) ); }; code_factor: '(' code_expr ')' final { $$->expr = $2->expr; }; code_factor: KW_MakeTree '(' opt_code_expr_list ')' final { $$->expr = LangExpr::cons( LangTerm::cons( $1->loc, LangTerm::MakeTreeType, $3->exprVect ) ); }; code_factor: KW_MakeToken '(' opt_code_expr_list ')' final { $$->expr = LangExpr::cons( LangTerm::cons( $1->loc, LangTerm::MakeTokenType, $3->exprVect ) ); }; code_factor: KW_Deref code_expr final { $$->expr = LangExpr::cons( $1->loc, OP_Deref, $2->expr ); }; code_factor: string_list final { $$->expr = LangExpr::cons( LangTerm::cons( replItemList ) ); }; nonterm opt_field_init uses field_init_list; opt_field_init: '(' opt_field_init_list ')' final { $$->fieldInitVect = $2->fieldInitVect; }; opt_field_init: final { $$->fieldInitVect = 0; }; nonterm opt_field_init_list uses field_init_list; opt_field_init_list: field_init_list final { $$->fieldInitVect = $1->fieldInitVect; }; opt_field_init_list: final { $$->fieldInitVect = 0; }; nonterm field_init_list { FieldInitVect *fieldInitVect; }; field_init_list: field_init_list field_init final { $$->fieldInitVect = $1->fieldInitVect; $$->fieldInitVect->append( $2->fieldInit ); }; field_init_list: field_init final { $$->fieldInitVect = new FieldInitVect; $$->fieldInitVect->append( $1->fieldInit ); }; nonterm field_init { FieldInit *fieldInit; }; field_init: code_expr final { $$->fieldInit = new FieldInit( InputLoc(), "_name", $1->expr ); }; # # Regular Expressions # nonterm opt_rl_join uses rl_join; opt_rl_join: rl_join opt_context final { $$->join = $1->join; $$->context = $2->context; if ( $2->context != 0 ) { /* Create the enter and leaving actions that will mark the substring. */ Action *mark = Action::cons( MarkMark, pd->nextMatchEndNum++ ); pd->actionList.append( mark ); $$->join->context = $2->context; $$->join->mark = mark; } }; opt_rl_join: final { $$->join = 0; $$->context = 0; }; nonterm rl_join { Join *join; Join *context; }; rl_join: rl_join ',' rl_expr final { /* Append the expression to the list and return it. */ $1->join->exprList.append( $3->expression ); $$->join = $1->join; }; rl_join: rl_expr final { $$->join = new Join( $1->expression ); }; # Context at the end of a pattern that is not included in the match nonterm opt_context uses rl_join; opt_context: '@' rl_join final { $$->context = $2->join; }; opt_context: final { $$->context = 0; }; nonterm rl_expr { Expression *expression; }; rl_expr: rl_expr '|' rl_term_short final { $$->expression = Expression::cons( $1->expression, $3->term, Expression::OrType ); }; rl_expr: rl_expr '&' rl_term_short final { $$->expression = Expression::cons( $1->expression, $3->term, Expression::IntersectType ); }; # This priority specification overrides the innermost parsing strategy which # results ordered choice interpretation of the grammar. rl_expr: rl_expr '-' rl_term_short final { $$->expression = Expression::cons( $1->expression, $3->term, Expression::SubtractType ); }; rl_expr: rl_expr TK_DashDash rl_term_short final { $$->expression = Expression::cons( $1->expression, $3->term, Expression::StrongSubtractType ); }; rl_expr: rl_term_short final { $$->expression = Expression::cons( $1->term ); }; nonterm rl_term_short { Term *term; }; shortest rl_term_short; rl_term_short: rl_term final { $$->term = $1->term; }; nonterm rl_term { Term *term; }; rl_term: rl_term factor_with_label final { $$->term = Term::cons( $1->term, $2->factorWithAug ); }; rl_term: rl_term '.' factor_with_label final { $$->term = Term::cons( $1->term, $3->factorWithAug ); }; rl_term: rl_term TK_ColonGt factor_with_label final { $$->term = Term::cons( $1->term, $3->factorWithAug, Term::RightStartType ); }; rl_term: rl_term TK_ColonGtGt factor_with_label final { $$->term = Term::cons( $1->term, $3->factorWithAug, Term::RightFinishType ); }; rl_term: rl_term TK_LtColon factor_with_label final { $$->term = Term::cons( $1->term, $3->factorWithAug, Term::LeftType ); }; rl_term: factor_with_label final { $$->term = Term::cons( $1->factorWithAug ); }; nonterm factor_with_label { FactorWithAug *factorWithAug; }; factor_with_label: factor_with_ep final { $$->factorWithAug = $1->factorWithAug; }; factor_with_label: TK_Word ':' factor_with_label final { $$->factorWithAug = $3->factorWithAug; if ( pd->objectDef->checkRedecl( $1->data ) != 0 ) error($1->loc) << "label name \"" << $1->data << "\" already in use" << endp; /* Create the object field. */ NamespaceQual *qual = new NamespaceQual( namespaceStack.top(), regionStack.top() ); TypeRef *typeRef = TypeRef::cons( $1->loc, qual, "str" ); ObjField *objField = new ObjField( $1->loc, typeRef, $1->data ); /* Insert it into the map. */ pd->objectDef->insertField( $1->data, objField ); /* Create the enter and leaving actions that will mark the substring. */ Action *enter = Action::cons( MarkMark, pd->nextMatchEndNum++ ); Action *leave = Action::cons( MarkMark, pd->nextMatchEndNum++ ); pd->actionList.append( enter ); pd->actionList.append( leave ); /* Add entering and leaving actions. */ $$->factorWithAug->actions.append( ParserAction( $1->loc, at_start, 0, enter ) ); $$->factorWithAug->actions.append( ParserAction( $1->loc, at_leave, 0, leave ) ); reCaptureVect.append( ReCapture( enter, leave, objField ) ); }; nonterm factor_with_ep { FactorWithAug *factorWithAug; }; factor_with_ep: factor_with_aug final { $$->factorWithAug = $1->factorWithAug; }; nonterm factor_with_aug { FactorWithAug *factorWithAug; }; factor_with_aug: factor_with_rep final { $$->factorWithAug = FactorWithAug::cons( $1->factorWithRep ); }; # The fourth level of precedence. These are the trailing unary operators that # allow for repetition. nonterm factor_with_rep { FactorWithRep *factorWithRep; }; factor_with_rep: factor_with_rep '*' final { $$->factorWithRep = FactorWithRep::cons( $2->loc, $1->factorWithRep, 0, 0, FactorWithRep::StarType ); }; factor_with_rep: factor_with_rep TK_StarStar final { $$->factorWithRep = FactorWithRep::cons( $2->loc, $1->factorWithRep, 0, 0, FactorWithRep::StarStarType ); }; factor_with_rep: factor_with_rep '?' final { $$->factorWithRep = FactorWithRep::cons( $2->loc, $1->factorWithRep, 0, 0, FactorWithRep::OptionalType ); }; factor_with_rep: factor_with_rep '+' final { $$->factorWithRep = FactorWithRep::cons( $2->loc, $1->factorWithRep, 0, 0, FactorWithRep::PlusType ); }; factor_with_rep: factor_with_rep '{' factor_rep_num '}' final { $$->factorWithRep = FactorWithRep::cons( $2->loc, $1->factorWithRep, $3->rep, 0, FactorWithRep::ExactType ); }; factor_with_rep: factor_with_rep '{' ',' factor_rep_num '}' final { $$->factorWithRep = FactorWithRep::cons( $2->loc, $1->factorWithRep, 0, $4->rep, FactorWithRep::MaxType ); }; factor_with_rep: factor_with_rep '{' factor_rep_num ',' '}' final { $$->factorWithRep = FactorWithRep::cons( $2->loc, $1->factorWithRep, $3->rep, 0, FactorWithRep::MinType ); }; factor_with_rep: factor_with_rep '{' factor_rep_num ',' factor_rep_num '}' final { $$->factorWithRep = FactorWithRep::cons( $2->loc, $1->factorWithRep, $3->rep, $5->rep, FactorWithRep::RangeType ); }; factor_with_rep: factor_with_neg final { $$->factorWithRep = FactorWithRep::cons( $1->factorWithNeg->loc, $1->factorWithNeg ); }; nonterm factor_rep_num { int rep; }; factor_rep_num: TK_UInt final { // Convert the priority number to a long. Check for overflow. errno = 0; int rep = strtol( $1->data, 0, 10 ); if ( errno == ERANGE && rep == LONG_MAX ) { // Repetition too large. Recover by returing repetition 1. */ error($1->loc) << "repetition number " << $1->data << " overflows" << endl; $$->rep = 1; } else { // Cannot be negative, so no overflow. $$->rep = rep; } }; # # The fifth level up in precedence. Negation. # nonterm factor_with_neg { FactorWithNeg *factorWithNeg; }; factor_with_neg: '!' factor_with_neg final { $$->factorWithNeg = FactorWithNeg::cons( $1->loc, $2->factorWithNeg, FactorWithNeg::NegateType ); }; factor_with_neg: '^' factor_with_neg final { $$->factorWithNeg = FactorWithNeg::cons( $1->loc, $2->factorWithNeg, FactorWithNeg::CharNegateType ); }; factor_with_neg: rl_factor final { $$->factorWithNeg = FactorWithNeg::cons( $1->factor->loc, $1->factor ); }; nonterm rl_factor { Factor *factor; }; rl_factor: TK_Literal final { /* Create a new factor node going to a concat literal. */ $$->factor = Factor::cons( Literal::cons( $1->loc, $1->data, Literal::LitString ) ); }; rl_factor: alphabet_num final { /* Create a new factor node going to a literal number. */ $$->factor = Factor::cons( Literal::cons( $1->loc, $1->data, Literal::Number ) ); }; rl_factor: TK_Word final { /* Find the named graph. */ Namespace *nspace = namespaceStack.top(); while ( nspace != 0 ) { GraphDictEl *gdNode = nspace->rlMap.find( $1->data ); if ( gdNode != 0 ) { if ( gdNode->isInstance ) { /* Recover by retuning null as the factor node. */ error($1->loc) << "references to graph instantiations not allowed " "in expressions" << endl; $$->factor = 0; } else { /* Create a factor node that is a lookup of an expression. */ $$->factor = Factor::cons( $1->loc, gdNode->value ); } break; } nspace = nspace->parentNamespace; } if ( nspace == 0 ) { /* Recover by returning null as the factor node. */ error($1->loc) << "graph lookup of \"" << $1->data << "\" failed" << endl; $$->factor = 0; } }; rl_factor: TK_SqOpen regular_expr_or_data TK_SqClose final { /* Create a new factor node going to an OR expression. */ $$->factor = Factor::cons( ReItem::cons( $1->loc, $2->reOrBlock, ReItem::OrBlock ) ); }; rl_factor: TK_SqOpenNeg regular_expr_or_data TK_SqClose final { /* Create a new factor node going to a negated OR expression. */ $$->factor = Factor::cons( ReItem::cons( $1->loc, $2->reOrBlock, ReItem::NegOrBlock ) ); }; rl_factor: range_lit TK_DotDot range_lit final { /* Create a new factor node going to a range. */ $$->factor = Factor::cons( Range::cons( $1->literal, $3->literal ) ); }; rl_factor: '(' rl_join ')' final { /* Create a new factor going to a parenthesized join. */ $$->factor = Factor::cons( $2->join ); }; nonterm range_lit { Literal *literal; }; # Literals which can be the end points of ranges. range_lit: TK_Literal final { /* Range literas must have only one char. We restrict this in the parse tree. */ $$->literal = Literal::cons( $1->loc, $1->data, Literal::LitString ); }; range_lit: alphabet_num final { /* Create a new literal number. */ $$->literal = Literal::cons( $1->loc, $1->data, Literal::Number ); }; nonterm alphabet_num uses token_data; # Any form of a number that can be used as a basic machine. */ alphabet_num: TK_UInt final { $$->loc = $1->loc; $$->data = $1->data; }; alphabet_num: '-' TK_UInt final { $$->loc = $1->loc; $$->data = '+'; $$->data += $2->data; }; alphabet_num: TK_Hex final { $$->loc = $1->loc; $$->data = $1->data; }; # # Regular Expressions. # # The data inside of a [] expression in a regular expression. Accepts any # number of characters or ranges. */ nonterm regular_expr_or_data { ReOrBlock *reOrBlock; }; regular_expr_or_data: regular_expr_or_data regular_expr_or_char final { /* An optimization to lessen the tree size. If an or char is directly * under the left side on the right and the right side is another or * char then paste them together and return the left side. Otherwise * just put the two under a new or data node. */ if ( $2->reOrItem->type == ReOrItem::Data && $1->reOrBlock->type == ReOrBlock::RecurseItem && $1->reOrBlock->item->type == ReOrItem::Data ) { /* Append the right side to right side of the left and toss the * right side. */ $1->reOrBlock->item->data += $2->reOrItem->data; delete $2->reOrItem; $$->reOrBlock = $1->reOrBlock; } else { /* Can't optimize, put the left and right under a new node. */ $$->reOrBlock = ReOrBlock::cons( $1->reOrBlock, $2->reOrItem ); } }; regular_expr_or_data: final { $$->reOrBlock = ReOrBlock::cons(); }; # A single character inside of an or expression. Can either be a character or a # set of characters. nonterm regular_expr_or_char { ReOrItem *reOrItem; }; regular_expr_or_char: TK_ReChar final { $$->reOrItem = ReOrItem::cons( $1->loc, $1->data ); }; regular_expr_or_char: TK_ReChar TK_Dash TK_ReChar final { $$->reOrItem = ReOrItem::cons( $2->loc, $1->data[0], $3->data[0] ); }; # A local state reference. Cannot have :: prefix. local_state_ref: no_name_sep state_ref_names; # Clear the name ref structure. no_name_sep: final { nameRef.empty(); }; # A qualified state reference. state_ref: opt_name_sep state_ref_names; # Optional leading name separator. opt_name_sep: TK_NameSep final { /* Insert an initial null pointer val to indicate the existence of the * initial name seperator. */ nameRef.setAs( 0 ); }; opt_name_sep: final { nameRef.empty(); }; # List of names separated by :: state_ref_names: state_ref_names TK_NameSep TK_Word final { nameRef.append( $3->data ); }; state_ref_names: TK_Word final { nameRef.append( $1->data ); }; nonterm opt_commit { bool commit; }; opt_commit: final { $$->commit = false; }; opt_commit: KW_Commit final { $$->commit = true; }; # # Grammar Finished # write types; write data; }%% void ColmParser::init() { /* Set up the root namespace. */ const char *rootNamespaceName = "___ROOT_NAMESPACE"; Namespace *rootNamespace = new Namespace( InputLoc(), rootNamespaceName, pd->namespaceList.length(), 0 ); pd->namespaceList.append( rootNamespace ); namespaceStack.push( rootNamespace ); pd->rootNamespace = rootNamespace; /* Set up the root token region. */ const char *rootRegionName = "___ROOT_REGION"; TokenRegion *rootRegion = new TokenRegion( InputLoc(), rootRegionName, pd->regionList.length(), 0 ); pd->regionList.append( rootRegion ); addRegionDef( InputLoc(), namespaceStack.top(), rootRegionName, rootRegion ); regionStack.push( rootRegion ); pd->rootRegion = rootRegion; /* Set up the global object. */ String global = "global"; pd->globalObjectDef = new ObjectDef( ObjectDef::UserType, global, pd->nextObjectId++ ); /* The eofTokenRegion defaults to the root region. */ pd->eofTokenRegion = rootRegion; /* Initialize the dictionary of graphs. This is our symbol table. The * initialization needs to be done on construction which happens at the * beginning of a machine spec so any assignment operators can reference * the builtins. */ pd->initGraphDict(); pd->rootLocalFrame = new ObjectDef( ObjectDef::FrameType, "local", pd->nextObjectId++ ); pd->curLocalFrame = pd->rootLocalFrame; %% write init; addArgvList(); } void ColmParser::addArgvList() { NamespaceQual *nspaceQual1 = new NamespaceQual( namespaceStack.top(), regionStack.top() ); TypeRef *typeRef = TypeRef::cons( InputLoc(), nspaceQual1, "str" ); NamespaceQual *nspaceQual2 = new NamespaceQual( namespaceStack.top(), regionStack.top() ); pd->argvTypeRef = TypeRef::cons( TypeRef::List, InputLoc(), nspaceQual2, typeRef, 0 ); } int ColmParser::parseLangEl( int type, const Token *token ) { %% write exec; return errCount == 0 ? 0 : -1; } void ColmParser::addRegularDef( const InputLoc &loc, Namespace *nspace, const String &name, Join *join ) { GraphDictEl *newEl = nspace->rlMap.insert( name ); if ( newEl != 0 ) { /* New element in the dict, all good. */ newEl->value = new VarDef( name, join ); newEl->isInstance = false; newEl->loc = loc; } else { // Recover by ignoring the duplicate. error(loc) << "regular definition \"" << name << "\" already exists" << endl; } } TokenRegion *ColmParser::createRegion( String &scannerName ) { TokenRegion *tokenRegion = new TokenRegion( InputLoc(), scannerName, pd->regionList.length(), regionStack.top() ); regionStack.top()->childRegions.append( tokenRegion ); pd->regionList.append( tokenRegion ); addRegionDef( InputLoc(), namespaceStack.top(), scannerName, tokenRegion ); return tokenRegion; } void ColmParser::addRegionDef( const InputLoc &loc, Namespace *nspace, const String &name, TokenRegion *tokenRegion ) { RegionGraphDictEl *newEl = nspace->graphDict.insert( name ); if ( newEl != 0 ) { /* New element in the dict, all good. */ newEl->value = new RegionDef( name, tokenRegion ); newEl->isInstance = true; newEl->loc = loc; /* It it is an instance, put on the instance list. */ pd->instanceList.append( newEl ); } else { // Recover by ignoring the duplicate. error(loc) << "regular definition \"" << name << "\" already exists" << endl; } } ostream &ColmParser::parse_error( int tokId, Token &token ) { /* Maintain the error count. */ gblErrorCount += 1; cerr << token.loc.fileName << ":" << token.loc.line << ":" << token.loc.col << ": "; cerr << "at token "; if ( tokId < 128 ) cerr << "\"" << ColmParser_lelNames[tokId] << "\""; else cerr << ColmParser_lelNames[tokId]; if ( token.data != 0 ) cerr << " with data \"" << token.data << "\""; cerr << ": "; return cerr; } int ColmParser::token( InputLoc &loc, int tokId, char *tokstart, int toklen ) { Token token; if ( toklen > 0 ) token.data.setAs( tokstart, toklen ); token.loc = loc; int res = parseLangEl( tokId, &token ); if ( res < 0 ) { parse_error(tokId, token) << "parse error" << endl; exit(1); } return res; }