📄 grammar.java
字号:
if ( r!=null ) { defineLabel(r, label, element, TOKEN_LIST_LABEL); } } public void defineRuleListLabel(String ruleName, antlr.Token label, GrammarAST element) { Rule r = getRule(ruleName); if ( r!=null ) { if ( !r.getHasMultipleReturnValues() ) { ErrorManager.grammarError( ErrorManager.MSG_LIST_LABEL_INVALID_UNLESS_RETVAL_STRUCT,this, label,label.getText()); } defineLabel(r, label, element, RULE_LIST_LABEL); } } /** Track a rule reference within an outermost alt of a rule. Used * at the moment to decide if $ruleref refers to a unique rule ref in * the alt. Rewrite rules force tracking of all rule AST results. * * This data is also used to verify that all rules have been defined. */ public void altReferencesRule(String ruleName, GrammarAST refAST, int outerAltNum) { Rule r = getRule(ruleName); if ( r==null ) { return; } r.trackRuleReferenceInAlt(refAST, outerAltNum); antlr.Token refToken = refAST.getToken(); if ( !ruleRefs.contains(refToken) ) { ruleRefs.add(refToken); } } /** Track a token reference within an outermost alt of a rule. Used * to decide if $tokenref refers to a unique token ref in * the alt. Does not track literals! * * Rewrite rules force tracking of all tokens. */ public void altReferencesTokenID(String ruleName, GrammarAST refAST, int outerAltNum) { Rule r = getRule(ruleName); if ( r==null ) { return; } r.trackTokenReferenceInAlt(refAST, outerAltNum); if ( !tokenIDRefs.contains(refAST.getToken()) ) { tokenIDRefs.add(refAST.getToken()); } } /** To yield smaller, more readable code, track which rules have their * predefined attributes accessed. If the rule has no user-defined * return values, then don't generate the return value scope classes * etc... Make the rule have void return value. Don't track for lexer * rules. */ public void referenceRuleLabelPredefinedAttribute(String ruleName) { Rule r = getRule(ruleName); if ( r!=null && type!=LEXER ) { // indicate that an action ref'd an attr unless it's in a lexer // so that $ID.text refs don't force lexer rules to define // return values...Token objects are created by the caller instead. r.referencedPredefinedRuleAttributes = true; } } public void checkRuleReference(GrammarAST refAST, GrammarAST argsAST, String currentRuleName) { Rule r = getRule(refAST.getText()); if ( refAST.getType()==ANTLRParser.RULE_REF ) { if ( argsAST!=null ) { // rule[args]; ref has args if ( r!=null && r.argActionAST==null ) { // but rule def has no args ErrorManager.grammarError( ErrorManager.MSG_RULE_HAS_NO_ARGS, this, argsAST.getToken(), r.name); } } else { // rule ref has no args if ( r!=null && r.argActionAST!=null ) { // but rule def has args ErrorManager.grammarError( ErrorManager.MSG_MISSING_RULE_ARGS, this, refAST.getToken(), r.name); } } } else if ( refAST.getType()==ANTLRParser.TOKEN_REF ) { if ( type!=LEXER ) { if ( argsAST!=null ) { // args on a token ref not in a lexer rule ErrorManager.grammarError( ErrorManager.MSG_ARGS_ON_TOKEN_REF, this, refAST.getToken(), refAST.getText()); } return; // ignore token refs in nonlexers } if ( argsAST!=null ) { // tokenRef[args]; ref has args if ( r!=null && r.argActionAST==null ) { // but token rule def has no args ErrorManager.grammarError( ErrorManager.MSG_RULE_HAS_NO_ARGS, this, argsAST.getToken(), r.name); } } else { // token ref has no args if ( r!=null && r.argActionAST!=null ) { // but token rule def has args ErrorManager.grammarError( ErrorManager.MSG_MISSING_RULE_ARGS, this, refAST.getToken(), r.name); } } } } /** Return a list of left-recursive rules; no analysis can be done * successfully on these. Useful to skip these rules then and also * for ANTLRWorks to highlight them. */ public Set getLeftRecursiveRules() { if ( nfa==null ) { createNFAs(); } if ( leftRecursiveRules!=null ) { return leftRecursiveRules; } checkAllRulesForLeftRecursion(); return leftRecursiveRules; } /** Check all rules for infinite left recursion before analysis. Return list * of troublesome rule cycles. This method has two side-effects: it notifies * the error manager that we have problems and it sets the list of * recursive rules that we should ignore during analysis. * * Return type: List<Set<String(rule-name)>>. */ public List checkAllRulesForLeftRecursion() { createNFAs(); // make sure we have NFAs leftRecursiveRules = new HashSet(); List listOfRecursiveCycles = new ArrayList(); // List<Set<String(rule-name)>> for (int i = 0; i < ruleIndexToRuleList.size(); i++) { String ruleName = (String)ruleIndexToRuleList.elementAt(i); if ( ruleName!=null ) { NFAState s = getRuleStartState(ruleName); visitedDuringRecursionCheck = new HashSet(); visitedDuringRecursionCheck.add(ruleName); Set visitedStates = new HashSet(); traceStatesLookingForLeftRecursion(s, visitedStates, listOfRecursiveCycles); } } if ( listOfRecursiveCycles.size()>0 ) { ErrorManager.leftRecursionCycles(listOfRecursiveCycles); } return listOfRecursiveCycles; } /** From state s, look for any transition to a rule that is currently * being traced. When tracing r, visitedDuringRecursionCheck has r * initially. If you reach an accept state, return but notify the * invoking rule that it is nullable, which implies that invoking * rule must look at follow transition for that invoking state. * The visitedStates tracks visited states within a single rule so * we can avoid epsilon-loop-induced infinite recursion here. Keep * filling the cycles in listOfRecursiveCycles and also, as a * side-effect, set leftRecursiveRules. */ protected boolean traceStatesLookingForLeftRecursion(NFAState s, Set visitedStates, List listOfRecursiveCycles) { if ( s.isAcceptState() ) { // this rule must be nullable! // At least one epsilon edge reached accept state return true; } if ( visitedStates.contains(s) ) { // within same rule, we've hit same state; quit looping return false; } visitedStates.add(s); boolean stateReachesAcceptState = false; Transition t0 = s.transition(0); if ( t0 instanceof RuleClosureTransition ) { String targetRuleName = ((NFAState)t0.target).getEnclosingRule(); if ( visitedDuringRecursionCheck.contains(targetRuleName) ) { // record left-recursive rule, but don't go back in leftRecursiveRules.add(targetRuleName); /* System.out.println("already visited "+targetRuleName+", calling from "+ s.getEnclosingRule()); */ addRulesToCycle(targetRuleName, s.getEnclosingRule(), listOfRecursiveCycles); } else { // must visit if not already visited; send new visitedStates set visitedDuringRecursionCheck.add(targetRuleName); boolean callReachedAcceptState = traceStatesLookingForLeftRecursion((NFAState)t0.target, new HashSet(), listOfRecursiveCycles); // we're back from visiting that rule visitedDuringRecursionCheck.remove(targetRuleName); // must keep going in this rule then if ( callReachedAcceptState ) { NFAState followingState = ((RuleClosureTransition)t0).getFollowState(); stateReachesAcceptState |= traceStatesLookingForLeftRecursion(followingState, visitedStates, listOfRecursiveCycles); } } } else if ( t0.label.isEpsilon() ) { stateReachesAcceptState |= traceStatesLookingForLeftRecursion((NFAState)t0.target, visitedStates, listOfRecursiveCycles); } // else it has a labeled edge // now do the other transition if it exists Transition t1 = s.transition(1); if ( t1!=null ) { stateReachesAcceptState |= traceStatesLookingForLeftRecursion((NFAState)t1.target, visitedStates, listOfRecursiveCycles); } return stateReachesAcceptState; } /** enclosingRuleName calls targetRuleName, find the cycle containing * the target and add the caller. Find the cycle containing the caller * and add the target. If no cycles contain either, then create a new * cycle. listOfRecursiveCycles is List<Set<String>> that holds a list * of cycles (sets of rule names). */ protected void addRulesToCycle(String targetRuleName, String enclosingRuleName, List listOfRecursiveCycles) { boolean foundCycle = false; for (int i = 0; i < listOfRecursiveCycles.size(); i++) { Set rulesInCycle = (Set)listOfRecursiveCycles.get(i); // ensure both rules are in same cycle if ( rulesInCycle.contains(targetRuleName) ) { rulesInCycle.add(enclosingRuleName); foundCycle = true; } if ( rulesInCycle.contains(enclosingRuleName) ) { rulesInCycle.add(targetRuleName); foundCycle = true; } } if ( !foundCycle ) { Set cycle = new HashSet(); cycle.add(targetRuleName); cycle.add(enclosingRuleName); listOfRecursiveCycles.add(cycle); } } /** Rules like "a : ;" and "a : {...} ;" should not generate * try/catch blocks for RecognitionException. To detect this * it's probably ok to just look for any reference to an atom * that can match some input. W/o that, the rule is unlikey to have * any else. */ public boolean isEmptyRule(GrammarAST block) { GrammarAST aTokenRefNode = block.findFirstType(ANTLRParser.TOKEN_REF); GrammarAST aStringLiteralRefNode = block.findFirstType(ANTLRParser.STRING_LITERAL); GrammarAST aCharLiteralRefNode = block.findFirstType(ANTLRParser.CHAR_LITERAL); GrammarAST aWildcardRefNode = block.findFirstType(ANTLRParser.WILDCARD); GrammarAST aRuleRefNode = block.findFirstType(ANTLRParser.RULE_REF); if ( aTokenRefNode==null&& aStringLiteralRefNode==null&& aCharLiteralRefNode==null&& aWildcardRefNode==null&& aRuleRefNode==null ) { return true; } return false; } public int getTokenType(String tokenName) { Integer I = null; if ( tokenName.charAt(0)=='\'') { I = (Integer)stringLiteralToTypeMap.get(tokenName); } else { // must be a label like ID I = (Integer)tokenIDToTypeMap.get(tokenName); } int i = (I!=null)?I.intValue():Label.INVALID; //System.out.println("grammar type "+type+" "+tokenName+"->"+i); return i; } /** Get the list of tokens that are IDs like BLOCK and LPAREN */ public Set getTokenIDs() { return tokenIDToTypeMap.keySet(); } /** Return an ordered integer list of token types that have no * corresponding token ID like INT or KEYWORD_BEGIN; for stuff * like 'begin'. */ public Collection getTokenTypesWithoutID() { List types = new ArrayList(); for (int t =Label.MIN_TOKEN_TYPE; t<=getMaxTokenType(); t++) { String name = getTokenDisplayName(t); if ( name.charAt(0)=='\'' ) { types.add(Utils.integer(t)); } } return types; } /** Get a list of all token IDs and literals that have an associated * token type. */ public Set getTokenDisplayNames() { Set names = new HashSet(); for (int t =Label.MIN_TOKEN_TYPE; t <=getMaxTokenType(); t++) { names.add(getTokenDisplayName(t)); } return names; } /** Given a literal like (the 3 char sequence with single quotes) 'a', * return the int value of 'a'. Convert escape sequences here also. * ANTLR's antlr.g parser does not convert escape sequences. * * 11/26/2005: I changed literals to always be '...' even for strings. * This routine still works though. */ public static int getCharValueFromGrammarCharLiteral(String literal) { if ( literal.length()==3 ) { // 'x' return literal.charAt(1); // no escape char } else if ( literal.length() == 4 ) { // '\x' (antlr lexer will catch invalid char) int escChar = literal.charAt(2); int charVal = ANTLRLiteralEscapedCharValue[escChar]; if ( charVal==0 ) { // Unnecessary escapes like '\{' should just yield { return escChar; } return charVal; } else if( literal.length() == 8 ) { // '\u1234' String unicodeChars = literal.substring(3,literal.length()-1); return Integer.parseInt(unicodeChars, 16); } ErrorManager.assertTrue(false, "invalid char literal: "+literal); return -1; } /** ANTLR does not convert escape sequences during the parse phase because * it could not know how to print String/char literals back out when * printing grammars etc... Someone in China might use the real unicode * char in a literal as it will display on their screen; when printing * back out, I could not know whether to display or use a unicode escape. * * This routine converts a string literal with possible escape sequences
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -