📄 codegenerator.java
字号:
outputFileST.setAttribute("generatedTimestamp", Tool.getCurrentTimeStamp()); headerFileST.setAttribute("generatedTimestamp", Tool.getCurrentTimeStamp()); // GENERATE RECOGNIZER // Walk the AST holding the input grammar, this time generating code // Decisions are generated by using the precomputed DFAs // Fill in the various templates with data CodeGenTreeWalker gen = new CodeGenTreeWalker(); try { gen.grammar((AST)grammar.getGrammarTree(), grammar, recognizerST, outputFileST, headerFileST); } catch (RecognitionException re) { ErrorManager.error(ErrorManager.MSG_BAD_AST_STRUCTURE, re); } genTokenTypeConstants(recognizerST); genTokenTypeConstants(outputFileST); genTokenTypeConstants(headerFileST); if ( grammar.type!=Grammar.LEXER ) { genTokenTypeNames(recognizerST); genTokenTypeNames(outputFileST); genTokenTypeNames(headerFileST); } // Now that we know what synpreds are used, we can set into template Set synpredNames = null; if ( grammar.synPredNamesUsedInDFA.size()>0 ) { synpredNames = grammar.synPredNamesUsedInDFA; } outputFileST.setAttribute("synpreds", synpredNames); headerFileST.setAttribute("synpreds", synpredNames); // all recognizers can see Grammar object recognizerST.setAttribute("grammar", grammar); // WRITE FILES try { target.genRecognizerFile(tool,this,grammar,outputFileST); if ( templates.isDefined("headerFile") ) { StringTemplate extST = templates.getInstanceOf("headerFileExtension"); target.genRecognizerHeaderFile(tool,this,grammar,headerFileST,extST.toString()); } // write out the vocab interchange file; used by antlr, // does not change per target StringTemplate tokenVocabSerialization = genTokenVocabOutput(); String vocabFileName = getVocabFileName(); if ( vocabFileName!=null ) { write(tokenVocabSerialization, vocabFileName); } //System.out.println(outputFileST.getDOTForDependencyGraph(false)); } catch (IOException ioe) { ErrorManager.error(ErrorManager.MSG_CANNOT_WRITE_FILE, getVocabFileName(), ioe); } /* System.out.println("num obj.prop refs: "+ ASTExpr.totalObjPropRefs); System.out.println("num reflection lookups: "+ ASTExpr.totalReflectionLookups); */ return outputFileST; } /** Some targets will have some extra scopes like C++ may have * '@headerfile:name {action}' or something. Make sure the * target likes the scopes in action table. */ protected void verifyActionScopesOkForTarget(Map actions) { Set actionScopeKeySet = actions.keySet(); for (Iterator it = actionScopeKeySet.iterator(); it.hasNext();) { String scope = (String)it.next(); if ( !target.isValidActionScope(grammar.type, scope) ) { // get any action from the scope to get error location Map scopeActions = (Map)actions.get(scope); GrammarAST actionAST = (GrammarAST)scopeActions.values().iterator().next(); ErrorManager.grammarError( ErrorManager.MSG_INVALID_ACTION_SCOPE,grammar, actionAST.getToken(),scope, Grammar.grammarTypeToString[grammar.type]); } } } /** Actions may reference $x::y attributes, call translateAction on * each action and replace that action in the Map. */ protected void translateActionAttributeReferences(Map actions) { Set actionScopeKeySet = actions.keySet(); for (Iterator it = actionScopeKeySet.iterator(); it.hasNext();) { String scope = (String)it.next(); Map scopeActions = (Map)actions.get(scope); translateActionAttributeReferencesForSingleScope(null,scopeActions); } } /** Use for translating rule @init{...} actions that have no scope */ protected void translateActionAttributeReferencesForSingleScope( Rule r, Map scopeActions) { String ruleName=null; if ( r!=null ) { ruleName = r.name; } Set actionNameSet = scopeActions.keySet(); for (Iterator nameIT = actionNameSet.iterator(); nameIT.hasNext();) { String name = (String) nameIT.next(); GrammarAST actionAST = (GrammarAST)scopeActions.get(name); List chunks = translateAction(ruleName,actionAST); scopeActions.put(name, chunks); // replace with translation } } /** Error recovery in ANTLR recognizers. * * Based upon original ideas: * * Algorithms + Data Structures = Programs by Niklaus Wirth * * and * * A note on error recovery in recursive descent parsers: * http://portal.acm.org/citation.cfm?id=947902.947905 * * Later, Josef Grosch had some good ideas: * Efficient and Comfortable Error Recovery in Recursive Descent Parsers: * ftp://www.cocolab.com/products/cocktail/doca4.ps/ell.ps.zip * * Like Grosch I implemented local FOLLOW sets that are combined at run-time * upon error to avoid parsing overhead. */ public void generateLocalFOLLOW(GrammarAST referencedElementNode, String referencedElementName, String enclosingRuleName, int elementIndex) { NFAState followingNFAState = referencedElementNode.followingNFAState;/* System.out.print("compute FOLLOW "+referencedElementNode.toString()+ " for "+referencedElementName+"#"+elementIndex +" in "+ enclosingRuleName+ " line="+referencedElementNode.getLine());*/ LookaheadSet follow = null; if ( followingNFAState!=null ) { follow = grammar.LOOK(followingNFAState); } if ( follow==null ) { ErrorManager.internalError("no follow state or cannot compute follow"); follow = new LookaheadSet(); } //System.out.println(" "+follow); List tokenTypeList = null; long[] words = null; if ( follow.tokenTypeSet==null ) { words = new long[1]; tokenTypeList = new ArrayList(); } else { BitSet bits = BitSet.of(follow.tokenTypeSet); words = bits.toPackedArray(); tokenTypeList = follow.tokenTypeSet.toList(); } // use the target to convert to hex strings (typically) String[] wordStrings = new String[words.length]; for (int j = 0; j < words.length; j++) { long w = words[j]; wordStrings[j] = target.getTarget64BitStringFromValue(w); } recognizerST.setAttribute("bitsets.{name,inName,bits,tokenTypes,tokenIndex}", referencedElementName, enclosingRuleName, wordStrings, tokenTypeList, Utils.integer(elementIndex)); outputFileST.setAttribute("bitsets.{name,inName,bits,tokenTypes,tokenIndex}", referencedElementName, enclosingRuleName, wordStrings, tokenTypeList, Utils.integer(elementIndex)); headerFileST.setAttribute("bitsets.{name,inName,bits,tokenTypes,tokenIndex}", referencedElementName, enclosingRuleName, wordStrings, tokenTypeList, Utils.integer(elementIndex)); } // L O O K A H E A D D E C I S I O N G E N E R A T I O N /** Generate code that computes the predicted alt given a DFA. The * recognizerST can be either the main generated recognizerTemplate * for storage in the main parser file or a separate file. It's up to * the code that ultimately invokes the codegen.g grammar rule. * * Regardless, the output file and header file get a copy of the DFAs. */ public StringTemplate genLookaheadDecision(StringTemplate recognizerST, DFA dfa) { StringTemplate decisionST; // If we are doing inline DFA and this one is acyclic and LL(*) // I have to check for is-non-LL(*) because if non-LL(*) the cyclic // check is not done by DFA.verify(); that is, verify() avoids // doesStateReachAcceptState() if non-LL(*) if ( dfa.canInlineDecision() ) { decisionST = acyclicDFAGenerator.genFixedLookaheadDecision(getTemplates(), dfa); } else { // generate any kind of DFA here (cyclic or acyclic) dfa.createStateTables(this); outputFileST.setAttribute("cyclicDFAs", dfa); headerFileST.setAttribute("cyclicDFAs", dfa); decisionST = templates.getInstanceOf("dfaDecision"); String description = dfa.getNFADecisionStartState().getDescription(); description = target.getTargetStringLiteralFromString(description); if ( description!=null ) { decisionST.setAttribute("description", description); } decisionST.setAttribute("decisionNumber", Utils.integer(dfa.getDecisionNumber())); } return decisionST; } /** A special state is huge (too big for state tables) or has a predicated * edge. Generate a simple if-then-else. Cannot be an accept state as * they have no emanating edges. Don't worry about switch vs if-then-else * because if you get here, the state is super complicated and needs an * if-then-else. This is used by the new DFA scheme created June 2006. */ public StringTemplate generateSpecialState(DFAState s) { StringTemplate stateST; stateST = templates.getInstanceOf("cyclicDFAState"); stateST.setAttribute("needErrorClause", Boolean.valueOf(true)); stateST.setAttribute("semPredState", Boolean.valueOf(s.isResolvedWithPredicates())); stateST.setAttribute("stateNumber", s.stateNumber); stateST.setAttribute("decisionNumber", s.dfa.decisionNumber); boolean foundGatedPred = false; StringTemplate eotST = null; for (int i = 0; i < s.getNumberOfTransitions(); i++) { Transition edge = (Transition) s.transition(i); StringTemplate edgeST; if ( edge.label.getAtom()==Label.EOT ) { // this is the default clause; has to held until last edgeST = templates.getInstanceOf("eotDFAEdge"); stateST.removeAttribute("needErrorClause"); eotST = edgeST; } else { edgeST = templates.getInstanceOf("cyclicDFAEdge"); StringTemplate exprST = genLabelExpr(templates,edge,1); edgeST.setAttribute("labelExpr", exprST); } edgeST.setAttribute("edgeNumber", Utils.integer(i+1)); edgeST.setAttribute("targetStateNumber", Utils.integer(edge.target.stateNumber)); // stick in any gated predicates for any edge if not already a pred if ( !edge.label.isSemanticPredicate() ) { DFAState t = (DFAState)edge.target; SemanticContext preds = t.getGatedPredicatesInNFAConfigurations(); if ( preds!=null ) { foundGatedPred = true; StringTemplate predST = preds.genExpr(this, getTemplates(), t.dfa); edgeST.setAttribute("predicates", predST.toString()); } } if ( edge.label.getAtom()!=Label.EOT ) { stateST.setAttribute("edges", edgeST); } } if ( foundGatedPred ) { // state has >= 1 edge with a gated pred (syn or sem) // must rewind input first, set flag. stateST.setAttribute("semPredState", new Boolean(foundGatedPred)); } if ( eotST!=null ) { stateST.setAttribute("edges", eotST); } return stateST; } /** Generate an expression for traversing an edge. */ protected StringTemplate genLabelExpr(StringTemplateGroup templates, Transition edge, int k) { Label label = edge.label; if ( label.isSemanticPredicate() ) { return genSemanticPredicateExpr(templates, edge); } if ( label.isSet() ) { return genSetExpr(templates, label.getSet(), k, true); } // must be simple label StringTemplate eST = templates.getInstanceOf("lookaheadTest"); eST.setAttribute("atom", getTokenTypeAsTargetLabel(label.getAtom())); eST.setAttribute("atomAsInt", Utils.integer(label.getAtom())); eST.setAttribute("k", Utils.integer(k)); return eST; } protected StringTemplate genSemanticPredicateExpr(StringTemplateGroup templates, Transition edge) { DFA dfa = ((DFAState)edge.target).dfa; // which DFA are we in Label label = edge.label; SemanticContext semCtx = label.getSemanticContext(); return semCtx.genExpr(this,templates,dfa); } /** For intervals such as [3..3, 30..35], generate an expression that * tests the lookahead similar to LA(1)==3 || (LA(1)>=30&&LA(1)<=35) */ public StringTemplate genSetExpr(StringTemplateGroup templates, IntSet set, int k, boolean partOfDFA) { if ( !(set instanceof IntervalSet) ) { throw new IllegalArgumentException("unable to generate expressions for non IntervalSet objects"); } IntervalSet iset = (IntervalSet)set; if ( iset.getIntervals()==null || iset.getIntervals().size()==0 ) { StringTemplate emptyST = new StringTemplate(templates, ""); emptyST.setName("empty-set-expr"); return emptyST; } String testSTName = "lookaheadTest"; String testRangeSTName = "lookaheadRangeTest"; if ( !partOfDFA ) { testSTName = "isolatedLookaheadTest"; testRangeSTName = "isolatedLookaheadRangeTest"; } StringTemplate setST = templates.getInstanceOf("setTest"); Iterator iter = iset.getIntervals().iterator(); int rangeNumber = 1; while (iter.hasNext()) { Interval I = (Interval) iter.next(); int a = I.a; int b = I.b; StringTemplate eST; if ( a==b ) { eST = templates.getInstanceOf(testSTName); eST.setAttribute("atom", getTokenTypeAsTargetLabel(a)); eST.setAttribute("atomAsInt", Utils.integer(a)); //eST.setAttribute("k",Utils.integer(k)); } else { eST = templates.getInstanceOf(testRangeSTName); eST.setAttribute("lower",getTokenTypeAsTargetLabel(a)); eST.setAttribute("lowerAsInt", Utils.integer(a)); eST.setAttribute("upper",getTokenTypeAsTargetLabel(b)); eST.setAttribute("upperAsInt", Utils.integer(b)); eST.setAttribute("rangeNumber",Utils.integer(rangeNumber)); } eST.setAttribute("k",Utils.integer(k)); setST.setAttribute("ranges", eST); rangeNumber++; } return setST; } // T O K E N D E F I N I T I O N G E N E R A T I O N /** Set attributes tokens and literals attributes in the incoming * code template. This is not the token vocab interchange file, but * rather a list of token type ID needed by the recognizer. */ protected void genTokenTypeConstants(StringTemplate code) { // make constants for the token types Iterator tokenIDs = grammar.getTokenIDs().iterator(); while (tokenIDs.hasNext()) { String tokenID = (String) tokenIDs.next(); int tokenType = grammar.getTokenType(tokenID); if ( tokenType==Label.EOF || tokenType>=Label.MIN_TOKEN_TYPE ) { // don't do FAUX labels 'cept EOF code.setAttribute("tokens.{name,type}", tokenID, Utils.integer(tokenType));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -