summaryrefslogtreecommitdiff
path: root/tool/src/org/antlr/v4
diff options
context:
space:
mode:
authorEmmanuel Bourg <ebourg@apache.org>2015-09-30 23:36:28 +0200
committerEmmanuel Bourg <ebourg@apache.org>2015-09-30 23:36:28 +0200
commitbbb7bd0887717b544df1a50e3842ca64c3489941 (patch)
tree3423dfb0f105f33e5752dd43bb0cd83728ecd2d7 /tool/src/org/antlr/v4
parentcdbf09fa7db7d25d9ce65b92d0398c3a54a5fd5d (diff)
Imported Upstream version 4.5.1
Diffstat (limited to 'tool/src/org/antlr/v4')
-rw-r--r--tool/src/org/antlr/v4/Tool.java891
-rw-r--r--tool/src/org/antlr/v4/analysis/AnalysisPipeline.java118
-rw-r--r--tool/src/org/antlr/v4/analysis/LeftRecursionDetector.java154
-rw-r--r--tool/src/org/antlr/v4/analysis/LeftRecursiveRuleAltInfo.java62
-rw-r--r--tool/src/org/antlr/v4/analysis/LeftRecursiveRuleAnalyzer.java446
-rw-r--r--tool/src/org/antlr/v4/analysis/LeftRecursiveRuleTransformer.java276
-rw-r--r--tool/src/org/antlr/v4/automata/ATNFactory.java244
-rw-r--r--tool/src/org/antlr/v4/automata/ATNOptimizer.java170
-rw-r--r--tool/src/org/antlr/v4/automata/ATNPrinter.java139
-rw-r--r--tool/src/org/antlr/v4/automata/ATNVisitor.java61
-rw-r--r--tool/src/org/antlr/v4/automata/LexerATNFactory.java483
-rw-r--r--tool/src/org/antlr/v4/automata/ParserATNFactory.java797
-rw-r--r--tool/src/org/antlr/v4/automata/TailEpsilonRemover.java81
-rw-r--r--tool/src/org/antlr/v4/codegen/ActionTranslator.java322
-rw-r--r--tool/src/org/antlr/v4/codegen/BlankOutputModelFactory.java130
-rw-r--r--tool/src/org/antlr/v4/codegen/CodeGenPipeline.java127
-rw-r--r--tool/src/org/antlr/v4/codegen/CodeGenerator.java302
-rw-r--r--tool/src/org/antlr/v4/codegen/CodeGeneratorExtension.java96
-rw-r--r--tool/src/org/antlr/v4/codegen/DefaultOutputModelFactory.java127
-rw-r--r--tool/src/org/antlr/v4/codegen/LexerFactory.java36
-rw-r--r--tool/src/org/antlr/v4/codegen/OutputModelController.java500
-rw-r--r--tool/src/org/antlr/v4/codegen/OutputModelFactory.java130
-rw-r--r--tool/src/org/antlr/v4/codegen/OutputModelWalker.java166
-rw-r--r--tool/src/org/antlr/v4/codegen/ParserFactory.java367
-rw-r--r--tool/src/org/antlr/v4/codegen/SourceGenTriggers.g198
-rw-r--r--tool/src/org/antlr/v4/codegen/Target.java527
-rw-r--r--tool/src/org/antlr/v4/codegen/Wildcard.java40
-rw-r--r--tool/src/org/antlr/v4/codegen/model/Action.java83
-rw-r--r--tool/src/org/antlr/v4/codegen/model/AddToLabelList.java46
-rw-r--r--tool/src/org/antlr/v4/codegen/model/AltBlock.java51
-rw-r--r--tool/src/org/antlr/v4/codegen/model/ArgAction.java43
-rw-r--r--tool/src/org/antlr/v4/codegen/model/BaseListenerFile.java38
-rw-r--r--tool/src/org/antlr/v4/codegen/model/BaseVisitorFile.java38
-rw-r--r--tool/src/org/antlr/v4/codegen/model/CaptureNextToken.java41
-rw-r--r--tool/src/org/antlr/v4/codegen/model/CaptureNextTokenType.java42
-rw-r--r--tool/src/org/antlr/v4/codegen/model/Choice.java97
-rw-r--r--tool/src/org/antlr/v4/codegen/model/CodeBlockForAlt.java42
-rw-r--r--tool/src/org/antlr/v4/codegen/model/CodeBlockForOuterMostAlt.java54
-rw-r--r--tool/src/org/antlr/v4/codegen/model/DispatchMethod.java38
-rw-r--r--tool/src/org/antlr/v4/codegen/model/ElementFrequenciesVisitor.java166
-rw-r--r--tool/src/org/antlr/v4/codegen/model/ExceptionClause.java48
-rw-r--r--tool/src/org/antlr/v4/codegen/model/InvokeRule.java105
-rw-r--r--tool/src/org/antlr/v4/codegen/model/LL1AltBlock.java53
-rw-r--r--tool/src/org/antlr/v4/codegen/model/LL1Choice.java48
-rw-r--r--tool/src/org/antlr/v4/codegen/model/LL1Loop.java71
-rw-r--r--tool/src/org/antlr/v4/codegen/model/LL1OptionalBlock.java47
-rw-r--r--tool/src/org/antlr/v4/codegen/model/LL1OptionalBlockSingleAlt.java65
-rw-r--r--tool/src/org/antlr/v4/codegen/model/LL1PlusBlockSingleAlt.java58
-rw-r--r--tool/src/org/antlr/v4/codegen/model/LL1StarBlockSingleAlt.java54
-rw-r--r--tool/src/org/antlr/v4/codegen/model/LabeledOp.java40
-rw-r--r--tool/src/org/antlr/v4/codegen/model/LeftRecursiveRuleFunction.java76
-rw-r--r--tool/src/org/antlr/v4/codegen/model/Lexer.java58
-rw-r--r--tool/src/org/antlr/v4/codegen/model/LexerFile.java55
-rw-r--r--tool/src/org/antlr/v4/codegen/model/ListenerDispatchMethod.java41
-rw-r--r--tool/src/org/antlr/v4/codegen/model/ListenerFile.java87
-rw-r--r--tool/src/org/antlr/v4/codegen/model/Loop.java60
-rw-r--r--tool/src/org/antlr/v4/codegen/model/MatchNotSet.java41
-rw-r--r--tool/src/org/antlr/v4/codegen/model/MatchSet.java52
-rw-r--r--tool/src/org/antlr/v4/codegen/model/MatchToken.java63
-rw-r--r--tool/src/org/antlr/v4/codegen/model/ModelElement.java41
-rw-r--r--tool/src/org/antlr/v4/codegen/model/OptionalBlock.java46
-rw-r--r--tool/src/org/antlr/v4/codegen/model/OutputFile.java53
-rw-r--r--tool/src/org/antlr/v4/codegen/model/OutputModelObject.java49
-rw-r--r--tool/src/org/antlr/v4/codegen/model/Parser.java47
-rw-r--r--tool/src/org/antlr/v4/codegen/model/ParserFile.java63
-rw-r--r--tool/src/org/antlr/v4/codegen/model/PlusBlock.java58
-rw-r--r--tool/src/org/antlr/v4/codegen/model/Recognizer.java135
-rw-r--r--tool/src/org/antlr/v4/codegen/model/RuleActionFunction.java53
-rw-r--r--tool/src/org/antlr/v4/codegen/model/RuleElement.java45
-rw-r--r--tool/src/org/antlr/v4/codegen/model/RuleFunction.java290
-rw-r--r--tool/src/org/antlr/v4/codegen/model/RuleSempredFunction.java40
-rw-r--r--tool/src/org/antlr/v4/codegen/model/SemPred.java97
-rw-r--r--tool/src/org/antlr/v4/codegen/model/SerializedATN.java65
-rw-r--r--tool/src/org/antlr/v4/codegen/model/SrcOp.java82
-rw-r--r--tool/src/org/antlr/v4/codegen/model/StarBlock.java52
-rw-r--r--tool/src/org/antlr/v4/codegen/model/Sync.java52
-rw-r--r--tool/src/org/antlr/v4/codegen/model/TestSetInline.java84
-rw-r--r--tool/src/org/antlr/v4/codegen/model/ThrowEarlyExitException.java42
-rw-r--r--tool/src/org/antlr/v4/codegen/model/ThrowNoViableAlt.java44
-rw-r--r--tool/src/org/antlr/v4/codegen/model/ThrowRecognitionException.java53
-rw-r--r--tool/src/org/antlr/v4/codegen/model/VisitorDispatchMethod.java38
-rw-r--r--tool/src/org/antlr/v4/codegen/model/VisitorFile.java84
-rw-r--r--tool/src/org/antlr/v4/codegen/model/chunk/ActionChunk.java44
-rw-r--r--tool/src/org/antlr/v4/codegen/model/chunk/ActionTemplate.java43
-rw-r--r--tool/src/org/antlr/v4/codegen/model/chunk/ActionText.java43
-rw-r--r--tool/src/org/antlr/v4/codegen/model/chunk/ArgRef.java40
-rw-r--r--tool/src/org/antlr/v4/codegen/model/chunk/LabelRef.java42
-rw-r--r--tool/src/org/antlr/v4/codegen/model/chunk/ListLabelRef.java37
-rw-r--r--tool/src/org/antlr/v4/codegen/model/chunk/LocalRef.java42
-rw-r--r--tool/src/org/antlr/v4/codegen/model/chunk/NonLocalAttrRef.java47
-rw-r--r--tool/src/org/antlr/v4/codegen/model/chunk/QRetValueRef.java42
-rw-r--r--tool/src/org/antlr/v4/codegen/model/chunk/RetValueRef.java44
-rw-r--r--tool/src/org/antlr/v4/codegen/model/chunk/RulePropertyRef.java43
-rw-r--r--tool/src/org/antlr/v4/codegen/model/chunk/RulePropertyRef_ctx.java39
-rw-r--r--tool/src/org/antlr/v4/codegen/model/chunk/RulePropertyRef_parser.java40
-rw-r--r--tool/src/org/antlr/v4/codegen/model/chunk/RulePropertyRef_start.java40
-rw-r--r--tool/src/org/antlr/v4/codegen/model/chunk/RulePropertyRef_stop.java40
-rw-r--r--tool/src/org/antlr/v4/codegen/model/chunk/RulePropertyRef_text.java40
-rw-r--r--tool/src/org/antlr/v4/codegen/model/chunk/SetAttr.java48
-rw-r--r--tool/src/org/antlr/v4/codegen/model/chunk/SetNonLocalAttr.java49
-rw-r--r--tool/src/org/antlr/v4/codegen/model/chunk/ThisRulePropertyRef_ctx.java39
-rw-r--r--tool/src/org/antlr/v4/codegen/model/chunk/ThisRulePropertyRef_parser.java40
-rw-r--r--tool/src/org/antlr/v4/codegen/model/chunk/ThisRulePropertyRef_start.java40
-rw-r--r--tool/src/org/antlr/v4/codegen/model/chunk/ThisRulePropertyRef_stop.java40
-rw-r--r--tool/src/org/antlr/v4/codegen/model/chunk/ThisRulePropertyRef_text.java40
-rw-r--r--tool/src/org/antlr/v4/codegen/model/chunk/TokenPropertyRef.java43
-rw-r--r--tool/src/org/antlr/v4/codegen/model/chunk/TokenPropertyRef_channel.java40
-rw-r--r--tool/src/org/antlr/v4/codegen/model/chunk/TokenPropertyRef_index.java40
-rw-r--r--tool/src/org/antlr/v4/codegen/model/chunk/TokenPropertyRef_int.java40
-rw-r--r--tool/src/org/antlr/v4/codegen/model/chunk/TokenPropertyRef_line.java40
-rw-r--r--tool/src/org/antlr/v4/codegen/model/chunk/TokenPropertyRef_pos.java40
-rw-r--r--tool/src/org/antlr/v4/codegen/model/chunk/TokenPropertyRef_text.java40
-rw-r--r--tool/src/org/antlr/v4/codegen/model/chunk/TokenPropertyRef_type.java40
-rw-r--r--tool/src/org/antlr/v4/codegen/model/chunk/TokenRef.java43
-rw-r--r--tool/src/org/antlr/v4/codegen/model/dbg.java35
-rw-r--r--tool/src/org/antlr/v4/codegen/model/decl/AltLabelStructDecl.java78
-rw-r--r--tool/src/org/antlr/v4/codegen/model/decl/AttributeDecl.java45
-rw-r--r--tool/src/org/antlr/v4/codegen/model/decl/CodeBlock.java85
-rw-r--r--tool/src/org/antlr/v4/codegen/model/decl/ContextGetterDecl.java68
-rw-r--r--tool/src/org/antlr/v4/codegen/model/decl/ContextRuleGetterDecl.java42
-rw-r--r--tool/src/org/antlr/v4/codegen/model/decl/ContextRuleListGetterDecl.java44
-rw-r--r--tool/src/org/antlr/v4/codegen/model/decl/ContextRuleListIndexedGetterDecl.java44
-rw-r--r--tool/src/org/antlr/v4/codegen/model/decl/ContextTokenGetterDecl.java40
-rw-r--r--tool/src/org/antlr/v4/codegen/model/decl/ContextTokenListGetterDecl.java42
-rw-r--r--tool/src/org/antlr/v4/codegen/model/decl/ContextTokenListIndexedGetterDecl.java44
-rw-r--r--tool/src/org/antlr/v4/codegen/model/decl/Decl.java67
-rw-r--r--tool/src/org/antlr/v4/codegen/model/decl/ElementListDecl.java39
-rw-r--r--tool/src/org/antlr/v4/codegen/model/decl/RuleContextDecl.java44
-rw-r--r--tool/src/org/antlr/v4/codegen/model/decl/RuleContextListDecl.java40
-rw-r--r--tool/src/org/antlr/v4/codegen/model/decl/StructDecl.java112
-rw-r--r--tool/src/org/antlr/v4/codegen/model/decl/TokenDecl.java42
-rw-r--r--tool/src/org/antlr/v4/codegen/model/decl/TokenListDecl.java40
-rw-r--r--tool/src/org/antlr/v4/codegen/model/decl/TokenTypeDecl.java40
-rw-r--r--tool/src/org/antlr/v4/codegen/target/CSharpTarget.java177
-rw-r--r--tool/src/org/antlr/v4/codegen/target/JavaScriptTarget.java234
-rw-r--r--tool/src/org/antlr/v4/codegen/target/JavaTarget.java126
-rw-r--r--tool/src/org/antlr/v4/codegen/target/Python2Target.java136
-rw-r--r--tool/src/org/antlr/v4/codegen/target/Python3Target.java143
-rw-r--r--tool/src/org/antlr/v4/gui/BasicFontMetrics.java95
-rw-r--r--tool/src/org/antlr/v4/gui/GraphicsSupport.java138
-rw-r--r--tool/src/org/antlr/v4/gui/JFileChooserConfirmOverwrite.java63
-rw-r--r--tool/src/org/antlr/v4/gui/PostScriptDocument.java212
-rw-r--r--tool/src/org/antlr/v4/gui/SystemFontMetrics.java63
-rw-r--r--tool/src/org/antlr/v4/gui/TestRig.java270
-rw-r--r--tool/src/org/antlr/v4/gui/TreeLayoutAdaptor.java149
-rw-r--r--tool/src/org/antlr/v4/gui/TreePostScriptGenerator.java176
-rw-r--r--tool/src/org/antlr/v4/gui/TreeTextProvider.java37
-rw-r--r--tool/src/org/antlr/v4/gui/TreeViewer.java764
-rw-r--r--tool/src/org/antlr/v4/gui/Trees.java120
-rw-r--r--tool/src/org/antlr/v4/misc/CharSupport.java153
-rw-r--r--tool/src/org/antlr/v4/misc/FrequencySet.java52
-rw-r--r--tool/src/org/antlr/v4/misc/Graph.java117
-rw-r--r--tool/src/org/antlr/v4/misc/MutableInt.java56
-rw-r--r--tool/src/org/antlr/v4/misc/OrderedHashMap.java73
-rw-r--r--tool/src/org/antlr/v4/misc/Utils.java171
-rw-r--r--tool/src/org/antlr/v4/parse/ANTLRLexer.g798
-rw-r--r--tool/src/org/antlr/v4/parse/ANTLRParser.g922
-rw-r--r--tool/src/org/antlr/v4/parse/ATNBuilder.g214
-rw-r--r--tool/src/org/antlr/v4/parse/ActionSplitter.g125
-rw-r--r--tool/src/org/antlr/v4/parse/ActionSplitterListener.java45
-rw-r--r--tool/src/org/antlr/v4/parse/BlockSetTransformer.g129
-rw-r--r--tool/src/org/antlr/v4/parse/GrammarASTAdaptor.java83
-rw-r--r--tool/src/org/antlr/v4/parse/GrammarToken.java98
-rw-r--r--tool/src/org/antlr/v4/parse/GrammarTreeVisitor.g1033
-rw-r--r--tool/src/org/antlr/v4/parse/LeftRecursiveRuleWalker.g224
-rw-r--r--tool/src/org/antlr/v4/parse/ResyncToEndOfRuleBlock.java37
-rw-r--r--tool/src/org/antlr/v4/parse/ScopeParser.java297
-rw-r--r--tool/src/org/antlr/v4/parse/TokenVocabParser.java175
-rw-r--r--tool/src/org/antlr/v4/parse/ToolANTLRLexer.java57
-rw-r--r--tool/src/org/antlr/v4/parse/ToolANTLRParser.java84
-rw-r--r--tool/src/org/antlr/v4/parse/v3TreeGrammarException.java42
-rw-r--r--tool/src/org/antlr/v4/parse/v4ParserException.java47
-rw-r--r--tool/src/org/antlr/v4/semantics/ActionSniffer.java113
-rw-r--r--tool/src/org/antlr/v4/semantics/AttributeChecks.java259
-rw-r--r--tool/src/org/antlr/v4/semantics/BasicSemanticChecks.java637
-rw-r--r--tool/src/org/antlr/v4/semantics/BlankActionSplitterListener.java75
-rw-r--r--tool/src/org/antlr/v4/semantics/RuleCollector.java138
-rw-r--r--tool/src/org/antlr/v4/semantics/SemanticPipeline.java300
-rw-r--r--tool/src/org/antlr/v4/semantics/SymbolChecks.java312
-rw-r--r--tool/src/org/antlr/v4/semantics/SymbolCollector.java213
-rw-r--r--tool/src/org/antlr/v4/semantics/UseDefAnalyzer.java119
-rw-r--r--tool/src/org/antlr/v4/tool/ANTLRMessage.java130
-rw-r--r--tool/src/org/antlr/v4/tool/ANTLRToolListener.java44
-rw-r--r--tool/src/org/antlr/v4/tool/Alternative.java163
-rw-r--r--tool/src/org/antlr/v4/tool/Attribute.java73
-rw-r--r--tool/src/org/antlr/v4/tool/AttributeDict.java108
-rw-r--r--tool/src/org/antlr/v4/tool/AttributeResolver.java71
-rw-r--r--tool/src/org/antlr/v4/tool/BuildDependencyGenerator.java273
-rw-r--r--tool/src/org/antlr/v4/tool/DOTGenerator.java486
-rw-r--r--tool/src/org/antlr/v4/tool/DefaultToolListener.java69
-rw-r--r--tool/src/org/antlr/v4/tool/ErrorManager.java322
-rw-r--r--tool/src/org/antlr/v4/tool/ErrorSeverity.java68
-rw-r--r--tool/src/org/antlr/v4/tool/ErrorType.java1100
-rw-r--r--tool/src/org/antlr/v4/tool/Grammar.java1343
-rw-r--r--tool/src/org/antlr/v4/tool/GrammarInterpreterRuleContext.java57
-rw-r--r--tool/src/org/antlr/v4/tool/GrammarParserInterpreter.java474
-rw-r--r--tool/src/org/antlr/v4/tool/GrammarSemanticsMessage.java52
-rw-r--r--tool/src/org/antlr/v4/tool/GrammarSyntaxMessage.java60
-rw-r--r--tool/src/org/antlr/v4/tool/GrammarTransformPipeline.java456
-rw-r--r--tool/src/org/antlr/v4/tool/LabelElementPair.java74
-rw-r--r--tool/src/org/antlr/v4/tool/LabelType.java45
-rw-r--r--tool/src/org/antlr/v4/tool/LeftRecursionCyclesMessage.java61
-rw-r--r--tool/src/org/antlr/v4/tool/LeftRecursiveRule.java175
-rw-r--r--tool/src/org/antlr/v4/tool/LexerGrammar.java85
-rw-r--r--tool/src/org/antlr/v4/tool/Rule.java364
-rw-r--r--tool/src/org/antlr/v4/tool/ToolMessage.java53
-rw-r--r--tool/src/org/antlr/v4/tool/ast/ActionAST.java58
-rw-r--r--tool/src/org/antlr/v4/tool/ast/AltAST.java66
-rw-r--r--tool/src/org/antlr/v4/tool/ast/BlockAST.java61
-rw-r--r--tool/src/org/antlr/v4/tool/ast/GrammarAST.java264
-rw-r--r--tool/src/org/antlr/v4/tool/ast/GrammarASTErrorNode.java56
-rw-r--r--tool/src/org/antlr/v4/tool/ast/GrammarASTVisitor.java68
-rw-r--r--tool/src/org/antlr/v4/tool/ast/GrammarASTWithOptions.java96
-rw-r--r--tool/src/org/antlr/v4/tool/ast/GrammarRootAST.java111
-rw-r--r--tool/src/org/antlr/v4/tool/ast/NotAST.java50
-rw-r--r--tool/src/org/antlr/v4/tool/ast/OptionalBlockAST.java59
-rw-r--r--tool/src/org/antlr/v4/tool/ast/PlusBlockAST.java58
-rw-r--r--tool/src/org/antlr/v4/tool/ast/PredAST.java49
-rw-r--r--tool/src/org/antlr/v4/tool/ast/QuantifierAST.java41
-rw-r--r--tool/src/org/antlr/v4/tool/ast/RangeAST.java50
-rw-r--r--tool/src/org/antlr/v4/tool/ast/RuleAST.java74
-rw-r--r--tool/src/org/antlr/v4/tool/ast/RuleElementAST.java35
-rw-r--r--tool/src/org/antlr/v4/tool/ast/RuleRefAST.java60
-rw-r--r--tool/src/org/antlr/v4/tool/ast/SetAST.java50
-rw-r--r--tool/src/org/antlr/v4/tool/ast/StarBlockAST.java58
-rw-r--r--tool/src/org/antlr/v4/tool/ast/TerminalAST.java50
226 files changed, 30544 insertions, 0 deletions
diff --git a/tool/src/org/antlr/v4/Tool.java b/tool/src/org/antlr/v4/Tool.java
new file mode 100644
index 0000000..2441268
--- /dev/null
+++ b/tool/src/org/antlr/v4/Tool.java
@@ -0,0 +1,891 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4;
+
+import org.antlr.runtime.ANTLRFileStream;
+import org.antlr.runtime.ANTLRStringStream;
+import org.antlr.runtime.CharStream;
+import org.antlr.runtime.CommonTokenStream;
+import org.antlr.runtime.ParserRuleReturnScope;
+import org.antlr.runtime.RecognitionException;
+import org.antlr.v4.analysis.AnalysisPipeline;
+import org.antlr.v4.automata.ATNFactory;
+import org.antlr.v4.automata.LexerATNFactory;
+import org.antlr.v4.automata.ParserATNFactory;
+import org.antlr.v4.codegen.CodeGenPipeline;
+import org.antlr.v4.codegen.CodeGenerator;
+import org.antlr.v4.misc.Graph;
+import org.antlr.v4.parse.ANTLRParser;
+import org.antlr.v4.parse.GrammarASTAdaptor;
+import org.antlr.v4.parse.GrammarTreeVisitor;
+import org.antlr.v4.parse.ToolANTLRLexer;
+import org.antlr.v4.parse.ToolANTLRParser;
+import org.antlr.v4.parse.v3TreeGrammarException;
+import org.antlr.v4.runtime.RuntimeMetaData;
+import org.antlr.v4.runtime.misc.LogManager;
+import org.antlr.v4.semantics.SemanticPipeline;
+import org.antlr.v4.tool.ANTLRMessage;
+import org.antlr.v4.tool.ANTLRToolListener;
+import org.antlr.v4.tool.BuildDependencyGenerator;
+import org.antlr.v4.tool.DOTGenerator;
+import org.antlr.v4.tool.DefaultToolListener;
+import org.antlr.v4.tool.ErrorManager;
+import org.antlr.v4.tool.ErrorType;
+import org.antlr.v4.tool.Grammar;
+import org.antlr.v4.tool.GrammarTransformPipeline;
+import org.antlr.v4.tool.LexerGrammar;
+import org.antlr.v4.tool.Rule;
+import org.antlr.v4.tool.ast.ActionAST;
+import org.antlr.v4.tool.ast.GrammarAST;
+import org.antlr.v4.tool.ast.GrammarASTErrorNode;
+import org.antlr.v4.tool.ast.GrammarRootAST;
+import org.antlr.v4.tool.ast.RuleAST;
+import org.antlr.v4.tool.ast.TerminalAST;
+import org.stringtemplate.v4.STGroup;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+public class Tool {
+ public static final String VERSION;
+ static {
+ // Assigned in a static{} block to prevent the field from becoming a
+ // compile-time constant
+ VERSION = RuntimeMetaData.VERSION;
+ }
+
+ public static final String GRAMMAR_EXTENSION = ".g4";
+ public static final String LEGACY_GRAMMAR_EXTENSION = ".g";
+
+ public static final List<String> ALL_GRAMMAR_EXTENSIONS =
+ Collections.unmodifiableList(Arrays.asList(GRAMMAR_EXTENSION, LEGACY_GRAMMAR_EXTENSION));
+
+ public static enum OptionArgType { NONE, STRING } // NONE implies boolean
+ public static class Option {
+ String fieldName;
+ String name;
+ OptionArgType argType;
+ String description;
+
+ public Option(String fieldName, String name, String description) {
+ this(fieldName, name, OptionArgType.NONE, description);
+ }
+
+ public Option(String fieldName, String name, OptionArgType argType, String description) {
+ this.fieldName = fieldName;
+ this.name = name;
+ this.argType = argType;
+ this.description = description;
+ }
+ }
+
+ // fields set by option manager
+
+ public File inputDirectory; // used by mvn plugin but not set by tool itself.
+ public String outputDirectory;
+ public String libDirectory;
+ public boolean generate_ATN_dot = false;
+ public String grammarEncoding = null; // use default locale's encoding
+ public String msgFormat = "antlr";
+ public boolean launch_ST_inspector = false;
+ public boolean ST_inspector_wait_for_close = false;
+ public boolean force_atn = false;
+ public boolean log = false;
+ public boolean gen_listener = true;
+ public boolean gen_visitor = false;
+ public boolean gen_dependencies = false;
+ public String genPackage = null;
+ public Map<String, String> grammarOptions = null;
+ public boolean warnings_are_errors = false;
+ public boolean longMessages = false;
+
+ public static Option[] optionDefs = {
+ new Option("outputDirectory", "-o", OptionArgType.STRING, "specify output directory where all output is generated"),
+ new Option("libDirectory", "-lib", OptionArgType.STRING, "specify location of grammars, tokens files"),
+ new Option("generate_ATN_dot", "-atn", "generate rule augmented transition network diagrams"),
+ new Option("grammarEncoding", "-encoding", OptionArgType.STRING, "specify grammar file encoding; e.g., euc-jp"),
+ new Option("msgFormat", "-message-format", OptionArgType.STRING, "specify output style for messages in antlr, gnu, vs2005"),
+ new Option("longMessages", "-long-messages", "show exception details when available for errors and warnings"),
+ new Option("gen_listener", "-listener", "generate parse tree listener (default)"),
+ new Option("gen_listener", "-no-listener", "don't generate parse tree listener"),
+ new Option("gen_visitor", "-visitor", "generate parse tree visitor"),
+ new Option("gen_visitor", "-no-visitor", "don't generate parse tree visitor (default)"),
+ new Option("genPackage", "-package", OptionArgType.STRING, "specify a package/namespace for the generated code"),
+ new Option("gen_dependencies", "-depend", "generate file dependencies"),
+ new Option("", "-D<option>=value", "set/override a grammar-level option"),
+ new Option("warnings_are_errors", "-Werror", "treat warnings as errors"),
+ new Option("launch_ST_inspector", "-XdbgST", "launch StringTemplate visualizer on generated code"),
+ new Option("ST_inspector_wait_for_close", "-XdbgSTWait", "wait for STViz to close before continuing"),
+ new Option("force_atn", "-Xforce-atn", "use the ATN simulator for all predictions"),
+ new Option("log", "-Xlog", "dump lots of logging info to antlr-timestamp.log"),
+ };
+
+ // helper vars for option management
+ protected boolean haveOutputDir = false;
+ protected boolean return_dont_exit = false;
+
+ // The internal options are for my use on the command line during dev
+ public static boolean internalOption_PrintGrammarTree = false;
+ public static boolean internalOption_ShowATNConfigsInDFA = false;
+
+
+ public final String[] args;
+
+ protected List<String> grammarFiles = new ArrayList<String>();
+
+ public ErrorManager errMgr;
+ public LogManager logMgr = new LogManager();
+
+ List<ANTLRToolListener> listeners = new CopyOnWriteArrayList<ANTLRToolListener>();
+
+ /** Track separately so if someone adds a listener, it's the only one
+ * instead of it and the default stderr listener.
+ */
+ DefaultToolListener defaultListener = new DefaultToolListener(this);
+
+ public static void main(String[] args) {
+ Tool antlr = new Tool(args);
+ if ( args.length == 0 ) { antlr.help(); antlr.exit(0); }
+
+ try {
+ antlr.processGrammarsOnCommandLine();
+ }
+ finally {
+ if ( antlr.log ) {
+ try {
+ String logname = antlr.logMgr.save();
+ System.out.println("wrote "+logname);
+ }
+ catch (IOException ioe) {
+ antlr.errMgr.toolError(ErrorType.INTERNAL_ERROR, ioe);
+ }
+ }
+ }
+ if ( antlr.return_dont_exit ) return;
+
+ if (antlr.errMgr.getNumErrors() > 0) {
+ antlr.exit(1);
+ }
+ antlr.exit(0);
+ }
+
+ public Tool() { this(null); }
+
+ public Tool(String[] args) {
+ this.args = args;
+ errMgr = new ErrorManager(this);
+ errMgr.setFormat(msgFormat);
+ handleArgs();
+ }
+
+ protected void handleArgs() {
+ int i=0;
+ while ( args!=null && i<args.length ) {
+ String arg = args[i];
+ i++;
+ if ( arg.startsWith("-D") ) { // -Dlanguage=Java syntax
+ handleOptionSetArg(arg);
+ continue;
+ }
+ if ( arg.charAt(0)!='-' ) { // file name
+ if ( !grammarFiles.contains(arg) ) grammarFiles.add(arg);
+ continue;
+ }
+ boolean found = false;
+ for (Option o : optionDefs) {
+ if ( arg.equals(o.name) ) {
+ found = true;
+ String argValue = null;
+ if ( o.argType==OptionArgType.STRING ) {
+ argValue = args[i];
+ i++;
+ }
+ // use reflection to set field
+ Class<? extends Tool> c = this.getClass();
+ try {
+ Field f = c.getField(o.fieldName);
+ if ( argValue==null ) {
+ if ( arg.startsWith("-no-") ) f.setBoolean(this, false);
+ else f.setBoolean(this, true);
+ }
+ else f.set(this, argValue);
+ }
+ catch (Exception e) {
+ errMgr.toolError(ErrorType.INTERNAL_ERROR, "can't access field "+o.fieldName);
+ }
+ }
+ }
+ if ( !found ) {
+ errMgr.toolError(ErrorType.INVALID_CMDLINE_ARG, arg);
+ }
+ }
+ if ( outputDirectory!=null ) {
+ if (outputDirectory.endsWith("/") ||
+ outputDirectory.endsWith("\\")) {
+ outputDirectory =
+ outputDirectory.substring(0, outputDirectory.length() - 1);
+ }
+ File outDir = new File(outputDirectory);
+ haveOutputDir = true;
+ if (outDir.exists() && !outDir.isDirectory()) {
+ errMgr.toolError(ErrorType.OUTPUT_DIR_IS_FILE, outputDirectory);
+ libDirectory = ".";
+ }
+ }
+ else {
+ outputDirectory = ".";
+ }
+ if ( libDirectory!=null ) {
+ if (libDirectory.endsWith("/") ||
+ libDirectory.endsWith("\\")) {
+ libDirectory = libDirectory.substring(0, libDirectory.length() - 1);
+ }
+ File outDir = new File(libDirectory);
+ if (!outDir.exists()) {
+ errMgr.toolError(ErrorType.DIR_NOT_FOUND, libDirectory);
+ libDirectory = ".";
+ }
+ }
+ else {
+ libDirectory = ".";
+ }
+ if ( launch_ST_inspector ) {
+ STGroup.trackCreationEvents = true;
+ return_dont_exit = true;
+ }
+ }
+
+ protected void handleOptionSetArg(String arg) {
+ int eq = arg.indexOf('=');
+ if ( eq>0 && arg.length()>3 ) {
+ String option = arg.substring("-D".length(), eq);
+ String value = arg.substring(eq+1);
+ if ( value.length()==0 ) {
+ errMgr.toolError(ErrorType.BAD_OPTION_SET_SYNTAX, arg);
+ return;
+ }
+ if ( Grammar.parserOptions.contains(option) ||
+ Grammar.lexerOptions.contains(option) )
+ {
+ if ( grammarOptions==null ) grammarOptions = new HashMap<String, String>();
+ grammarOptions.put(option, value);
+ }
+ else {
+ errMgr.grammarError(ErrorType.ILLEGAL_OPTION,
+ null,
+ null,
+ option);
+ }
+ }
+ else {
+ errMgr.toolError(ErrorType.BAD_OPTION_SET_SYNTAX, arg);
+ }
+ }
+
+ public void processGrammarsOnCommandLine() {
+ List<GrammarRootAST> sortedGrammars = sortGrammarByTokenVocab(grammarFiles);
+
+ for (GrammarRootAST t : sortedGrammars) {
+ final Grammar g = createGrammar(t);
+ g.fileName = t.fileName;
+ if ( gen_dependencies ) {
+ BuildDependencyGenerator dep =
+ new BuildDependencyGenerator(this, g);
+ /*
+ List outputFiles = dep.getGeneratedFileList();
+ List dependents = dep.getDependenciesFileList();
+ System.out.println("output: "+outputFiles);
+ System.out.println("dependents: "+dependents);
+ */
+ System.out.println(dep.getDependencies().render());
+
+ }
+ else if (errMgr.getNumErrors() == 0) {
+ process(g, true);
+ }
+ }
+ }
+
+ /** To process a grammar, we load all of its imported grammars into
+ subordinate grammar objects. Then we merge the imported rules
+ into the root grammar. If a root grammar is a combined grammar,
+ we have to extract the implicit lexer. Once all this is done, we
+ process the lexer first, if present, and then the parser grammar
+ */
+ public void process(Grammar g, boolean gencode) {
+ g.loadImportedGrammars();
+
+ GrammarTransformPipeline transform = new GrammarTransformPipeline(g, this);
+ transform.process();
+
+ LexerGrammar lexerg;
+ GrammarRootAST lexerAST;
+ if ( g.ast!=null && g.ast.grammarType== ANTLRParser.COMBINED &&
+ !g.ast.hasErrors )
+ {
+ lexerAST = transform.extractImplicitLexer(g); // alters g.ast
+ if ( lexerAST!=null ) {
+ if (grammarOptions != null) {
+ lexerAST.cmdLineOptions = grammarOptions;
+ }
+
+ lexerg = new LexerGrammar(this, lexerAST);
+ lexerg.fileName = g.fileName;
+ lexerg.originalGrammar = g;
+ g.implicitLexer = lexerg;
+ lexerg.implicitLexerOwner = g;
+ processNonCombinedGrammar(lexerg, gencode);
+// System.out.println("lexer tokens="+lexerg.tokenNameToTypeMap);
+// System.out.println("lexer strings="+lexerg.stringLiteralToTypeMap);
+ }
+ }
+ if ( g.implicitLexer!=null ) g.importVocab(g.implicitLexer);
+// System.out.println("tokens="+g.tokenNameToTypeMap);
+// System.out.println("strings="+g.stringLiteralToTypeMap);
+ processNonCombinedGrammar(g, gencode);
+ }
+
+ public void processNonCombinedGrammar(Grammar g, boolean gencode) {
+ if ( g.ast==null || g.ast.hasErrors ) return;
+ if ( internalOption_PrintGrammarTree ) System.out.println(g.ast.toStringTree());
+
+ boolean ruleFail = checkForRuleIssues(g);
+ if ( ruleFail ) return;
+
+ int prevErrors = errMgr.getNumErrors();
+ // MAKE SURE GRAMMAR IS SEMANTICALLY CORRECT (FILL IN GRAMMAR OBJECT)
+ SemanticPipeline sem = new SemanticPipeline(g);
+ sem.process();
+
+ String language = g.getOptionString("language");
+ if ( !CodeGenerator.targetExists(language) ) {
+ errMgr.toolError(ErrorType.CANNOT_CREATE_TARGET_GENERATOR, language);
+ return;
+ }
+
+ if ( errMgr.getNumErrors()>prevErrors ) return;
+
+ // BUILD ATN FROM AST
+ ATNFactory factory;
+ if ( g.isLexer() ) factory = new LexerATNFactory((LexerGrammar)g);
+ else factory = new ParserATNFactory(g);
+ g.atn = factory.createATN();
+
+ if ( generate_ATN_dot ) generateATNs(g);
+
+ // PERFORM GRAMMAR ANALYSIS ON ATN: BUILD DECISION DFAs
+ AnalysisPipeline anal = new AnalysisPipeline(g);
+ anal.process();
+
+ //if ( generate_DFA_dot ) generateDFAs(g);
+
+ if ( g.tool.getNumErrors()>prevErrors ) return;
+
+ // GENERATE CODE
+ if ( gencode ) {
+ CodeGenPipeline gen = new CodeGenPipeline(g);
+ gen.process();
+ }
+ }
+
+ /**
+ * Important enough to avoid multiple definitions that we do very early,
+ * right after AST construction. Also check for undefined rules in
+ * parser/lexer to avoid exceptions later. Return true if we find multiple
+ * definitions of the same rule or a reference to an undefined rule or
+ * parser rule ref in lexer rule.
+ */
+ public boolean checkForRuleIssues(final Grammar g) {
+ // check for redefined rules
+ GrammarAST RULES = (GrammarAST)g.ast.getFirstChildWithType(ANTLRParser.RULES);
+ List<GrammarAST> rules = new ArrayList<GrammarAST>(RULES.getAllChildrenWithType(ANTLRParser.RULE));
+ for (GrammarAST mode : g.ast.getAllChildrenWithType(ANTLRParser.MODE)) {
+ rules.addAll(mode.getAllChildrenWithType(ANTLRParser.RULE));
+ }
+
+ boolean redefinition = false;
+ final Map<String, RuleAST> ruleToAST = new HashMap<String, RuleAST>();
+ for (GrammarAST r : rules) {
+ RuleAST ruleAST = (RuleAST)r;
+ GrammarAST ID = (GrammarAST)ruleAST.getChild(0);
+ String ruleName = ID.getText();
+ RuleAST prev = ruleToAST.get(ruleName);
+ if ( prev !=null ) {
+ GrammarAST prevChild = (GrammarAST)prev.getChild(0);
+ g.tool.errMgr.grammarError(ErrorType.RULE_REDEFINITION,
+ g.fileName,
+ ID.getToken(),
+ ruleName,
+ prevChild.getToken().getLine());
+ redefinition = true;
+ continue;
+ }
+ ruleToAST.put(ruleName, ruleAST);
+ }
+
+ // check for undefined rules
+ class UndefChecker extends GrammarTreeVisitor {
+ public boolean badref = false;
+ @Override
+ public void tokenRef(TerminalAST ref) {
+ if ("EOF".equals(ref.getText())) {
+ // this is a special predefined reference
+ return;
+ }
+
+ if ( g.isLexer() ) ruleRef(ref, null);
+ }
+
+ @Override
+ public void ruleRef(GrammarAST ref, ActionAST arg) {
+ RuleAST ruleAST = ruleToAST.get(ref.getText());
+ String fileName = ref.getToken().getInputStream().getSourceName();
+ if (Character.isUpperCase(currentRuleName.charAt(0)) &&
+ Character.isLowerCase(ref.getText().charAt(0)))
+ {
+ badref = true;
+ errMgr.grammarError(ErrorType.PARSER_RULE_REF_IN_LEXER_RULE,
+ fileName, ref.getToken(), ref.getText(), currentRuleName);
+ }
+ else if ( ruleAST==null ) {
+ badref = true;
+ errMgr.grammarError(ErrorType.UNDEFINED_RULE_REF,
+ fileName, ref.token, ref.getText());
+ }
+ }
+ @Override
+ public ErrorManager getErrorManager() { return errMgr; }
+ }
+
+ UndefChecker chk = new UndefChecker();
+ chk.visitGrammar(g.ast);
+
+ return redefinition || chk.badref;
+ }
+
+ public List<GrammarRootAST> sortGrammarByTokenVocab(List<String> fileNames) {
+// System.out.println(fileNames);
+ Graph<String> g = new Graph<String>();
+ List<GrammarRootAST> roots = new ArrayList<GrammarRootAST>();
+ for (String fileName : fileNames) {
+ GrammarAST t = parseGrammar(fileName);
+ if ( t==null || t instanceof GrammarASTErrorNode) continue; // came back as error node
+ if ( ((GrammarRootAST)t).hasErrors ) continue;
+ GrammarRootAST root = (GrammarRootAST)t;
+ roots.add(root);
+ root.fileName = fileName;
+ String grammarName = root.getChild(0).getText();
+
+ GrammarAST tokenVocabNode = findOptionValueAST(root, "tokenVocab");
+ // Make grammars depend on any tokenVocab options
+ if ( tokenVocabNode!=null ) {
+ String vocabName = tokenVocabNode.getText();
+ g.addEdge(grammarName, vocabName);
+ }
+ // add cycle to graph so we always process a grammar if no error
+ // even if no dependency
+ g.addEdge(grammarName, grammarName);
+ }
+
+ List<String> sortedGrammarNames = g.sort();
+// System.out.println("sortedGrammarNames="+sortedGrammarNames);
+
+ List<GrammarRootAST> sortedRoots = new ArrayList<GrammarRootAST>();
+ for (String grammarName : sortedGrammarNames) {
+ for (GrammarRootAST root : roots) {
+ if ( root.getGrammarName().equals(grammarName) ) {
+ sortedRoots.add(root);
+ break;
+ }
+ }
+ }
+
+ return sortedRoots;
+ }
+
+ /** Manually get option node from tree; return null if no defined. */
+ public static GrammarAST findOptionValueAST(GrammarRootAST root, String option) {
+ GrammarAST options = (GrammarAST)root.getFirstChildWithType(ANTLRParser.OPTIONS);
+ if ( options!=null && options.getChildCount() > 0 ) {
+ for (Object o : options.getChildren()) {
+ GrammarAST c = (GrammarAST)o;
+ if ( c.getType() == ANTLRParser.ASSIGN &&
+ c.getChild(0).getText().equals(option) )
+ {
+ return (GrammarAST)c.getChild(1);
+ }
+ }
+ }
+ return null;
+ }
+
+
+ /** Given the raw AST of a grammar, create a grammar object
+ associated with the AST. Once we have the grammar object, ensure
+ that all nodes in tree referred to this grammar. Later, we will
+ use it for error handling and generally knowing from where a rule
+ comes from.
+ */
+ public Grammar createGrammar(GrammarRootAST ast) {
+ final Grammar g;
+ if ( ast.grammarType==ANTLRParser.LEXER ) g = new LexerGrammar(this, ast);
+ else g = new Grammar(this, ast);
+
+ // ensure each node has pointer to surrounding grammar
+ GrammarTransformPipeline.setGrammarPtr(g, ast);
+ return g;
+ }
+
+ public GrammarRootAST parseGrammar(String fileName) {
+ try {
+ File file = new File(fileName);
+ if (!file.isAbsolute()) {
+ file = new File(inputDirectory, fileName);
+ }
+
+ ANTLRFileStream in = new ANTLRFileStream(file.getAbsolutePath(), grammarEncoding);
+ GrammarRootAST t = parse(fileName, in);
+ return t;
+ }
+ catch (IOException ioe) {
+ errMgr.toolError(ErrorType.CANNOT_OPEN_FILE, ioe, fileName);
+ }
+ return null;
+ }
+
+ /** Convenience method to load and process an ANTLR grammar. Useful
+ * when creating interpreters. If you need to access to the lexer
+ * grammar created while processing a combined grammar, use
+ * getImplicitLexer() on returned grammar.
+ */
+ public Grammar loadGrammar(String fileName) {
+ GrammarRootAST grammarRootAST = parseGrammar(fileName);
+ final Grammar g = createGrammar(grammarRootAST);
+ g.fileName = fileName;
+ process(g, false);
+ return g;
+ }
+
+ private final Map<String, Grammar> importedGrammars = new HashMap<String, Grammar>();
+
+ /**
+ * Try current dir then dir of g then lib dir
+ * @param g
+ * @param nameNode The node associated with the imported grammar name.
+ */
+ public Grammar loadImportedGrammar(Grammar g, GrammarAST nameNode) throws IOException {
+ String name = nameNode.getText();
+ Grammar imported = importedGrammars.get(name);
+ if (imported == null) {
+ g.tool.log("grammar", "load " + name + " from " + g.fileName);
+ File importedFile = null;
+ for (String extension : ALL_GRAMMAR_EXTENSIONS) {
+ importedFile = getImportedGrammarFile(g, name + extension);
+ if (importedFile != null) {
+ break;
+ }
+ }
+
+ if ( importedFile==null ) {
+ errMgr.grammarError(ErrorType.CANNOT_FIND_IMPORTED_GRAMMAR, g.fileName, nameNode.getToken(), name);
+ return null;
+ }
+
+ String absolutePath = importedFile.getAbsolutePath();
+ ANTLRFileStream in = new ANTLRFileStream(absolutePath, grammarEncoding);
+ GrammarRootAST root = parse(g.fileName, in);
+ if (root == null) {
+ return null;
+ }
+
+ imported = createGrammar(root);
+ imported.fileName = absolutePath;
+ importedGrammars.put(root.getGrammarName(), imported);
+ }
+
+ return imported;
+ }
+
+ public GrammarRootAST parseGrammarFromString(String grammar) {
+ return parse("<string>", new ANTLRStringStream(grammar));
+ }
+
+ public GrammarRootAST parse(String fileName, CharStream in) {
+ try {
+ GrammarASTAdaptor adaptor = new GrammarASTAdaptor(in);
+ ToolANTLRLexer lexer = new ToolANTLRLexer(in, this);
+ CommonTokenStream tokens = new CommonTokenStream(lexer);
+ lexer.tokens = tokens;
+ ToolANTLRParser p = new ToolANTLRParser(tokens, this);
+ p.setTreeAdaptor(adaptor);
+ try {
+ ParserRuleReturnScope r = p.grammarSpec();
+ GrammarAST root = (GrammarAST)r.getTree();
+ if ( root instanceof GrammarRootAST) {
+ ((GrammarRootAST)root).hasErrors = lexer.getNumberOfSyntaxErrors()>0 || p.getNumberOfSyntaxErrors()>0;
+ assert ((GrammarRootAST)root).tokenStream == tokens;
+ if ( grammarOptions!=null ) {
+ ((GrammarRootAST)root).cmdLineOptions = grammarOptions;
+ }
+ return ((GrammarRootAST)root);
+ }
+ }
+ catch (v3TreeGrammarException e) {
+ errMgr.grammarError(ErrorType.V3_TREE_GRAMMAR, fileName, e.location);
+ }
+ return null;
+ }
+ catch (RecognitionException re) {
+ // TODO: do we gen errors now?
+ ErrorManager.internalError("can't generate this message at moment; antlr recovers");
+ }
+ return null;
+ }
+
+ public void generateATNs(Grammar g) {
+ DOTGenerator dotGenerator = new DOTGenerator(g);
+ List<Grammar> grammars = new ArrayList<Grammar>();
+ grammars.add(g);
+ List<Grammar> imported = g.getAllImportedGrammars();
+ if ( imported!=null ) grammars.addAll(imported);
+ for (Grammar ig : grammars) {
+ for (Rule r : ig.rules.values()) {
+ try {
+ String dot = dotGenerator.getDOT(g.atn.ruleToStartState[r.index], g.isLexer());
+ if (dot != null) {
+ writeDOTFile(g, r, dot);
+ }
+ }
+ catch (IOException ioe) {
+ errMgr.toolError(ErrorType.CANNOT_WRITE_FILE, ioe);
+ }
+ }
+ }
+ }
+
+ /** This method is used by all code generators to create new output
+ * files. If the outputDir set by -o is not present it will be created.
+ * The final filename is sensitive to the output directory and
+ * the directory where the grammar file was found. If -o is /tmp
+ * and the original grammar file was foo/t.g4 then output files
+ * go in /tmp/foo.
+ *
+ * The output dir -o spec takes precedence if it's absolute.
+ * E.g., if the grammar file dir is absolute the output dir is given
+ * precendence. "-o /tmp /usr/lib/t.g4" results in "/tmp/T.java" as
+ * output (assuming t.g4 holds T.java).
+ *
+ * If no -o is specified, then just write to the directory where the
+ * grammar file was found.
+ *
+ * If outputDirectory==null then write a String.
+ */
+ public Writer getOutputFileWriter(Grammar g, String fileName) throws IOException {
+ if (outputDirectory == null) {
+ return new StringWriter();
+ }
+ // output directory is a function of where the grammar file lives
+ // for subdir/T.g4, you get subdir here. Well, depends on -o etc...
+ File outputDir = getOutputDirectory(g.fileName);
+ File outputFile = new File(outputDir, fileName);
+
+ if (!outputDir.exists()) {
+ outputDir.mkdirs();
+ }
+ FileOutputStream fos = new FileOutputStream(outputFile);
+ OutputStreamWriter osw;
+ if ( grammarEncoding!=null ) {
+ osw = new OutputStreamWriter(fos, grammarEncoding);
+ }
+ else {
+ osw = new OutputStreamWriter(fos);
+ }
+ return new BufferedWriter(osw);
+ }
+
+ public File getImportedGrammarFile(Grammar g, String fileName) {
+ File importedFile = new File(inputDirectory, fileName);
+ if ( !importedFile.exists() ) {
+ File gfile = new File(g.fileName);
+ String parentDir = gfile.getParent();
+ importedFile = new File(parentDir, fileName);
+ if ( !importedFile.exists() ) { // try in lib dir
+ importedFile = new File(libDirectory, fileName);
+ if ( !importedFile.exists() ) {
+ return null;
+ }
+ }
+ }
+ return importedFile;
+ }
+
+ /**
+ * Return the location where ANTLR will generate output files for a given
+ * file. This is a base directory and output files will be relative to
+ * here in some cases such as when -o option is used and input files are
+ * given relative to the input directory.
+ *
+ * @param fileNameWithPath path to input source
+ */
+ public File getOutputDirectory(String fileNameWithPath) {
+ File outputDir;
+ String fileDirectory;
+
+ // Some files are given to us without a PATH but should should
+ // still be written to the output directory in the relative path of
+ // the output directory. The file directory is either the set of sub directories
+ // or just or the relative path recorded for the parent grammar. This means
+ // that when we write the tokens files, or the .java files for imported grammars
+ // taht we will write them in the correct place.
+ if (fileNameWithPath.lastIndexOf(File.separatorChar) == -1) {
+ // No path is included in the file name, so make the file
+ // directory the same as the parent grammar (which might sitll be just ""
+ // but when it is not, we will write the file in the correct place.
+ fileDirectory = ".";
+
+ }
+ else {
+ fileDirectory = fileNameWithPath.substring(0, fileNameWithPath.lastIndexOf(File.separatorChar));
+ }
+ if ( haveOutputDir ) {
+ // -o /tmp /var/lib/t.g4 => /tmp/T.java
+ // -o subdir/output /usr/lib/t.g4 => subdir/output/T.java
+ // -o . /usr/lib/t.g4 => ./T.java
+ if (fileDirectory != null &&
+ (new File(fileDirectory).isAbsolute() ||
+ fileDirectory.startsWith("~"))) { // isAbsolute doesn't count this :(
+ // somebody set the dir, it takes precendence; write new file there
+ outputDir = new File(outputDirectory);
+ }
+ else {
+ // -o /tmp subdir/t.g4 => /tmp/subdir/t.g4
+ if (fileDirectory != null) {
+ outputDir = new File(outputDirectory, fileDirectory);
+ }
+ else {
+ outputDir = new File(outputDirectory);
+ }
+ }
+ }
+ else {
+ // they didn't specify a -o dir so just write to location
+ // where grammar is, absolute or relative, this will only happen
+ // with command line invocation as build tools will always
+ // supply an output directory.
+ outputDir = new File(fileDirectory);
+ }
+ return outputDir;
+ }
+
+ protected void writeDOTFile(Grammar g, Rule r, String dot) throws IOException {
+ writeDOTFile(g, r.g.name + "." + r.name, dot);
+ }
+
+ protected void writeDOTFile(Grammar g, String name, String dot) throws IOException {
+ Writer fw = getOutputFileWriter(g, name + ".dot");
+ try {
+ fw.write(dot);
+ }
+ finally {
+ fw.close();
+ }
+ }
+
+ public void help() {
+ info("ANTLR Parser Generator Version " + Tool.VERSION);
+ for (Option o : optionDefs) {
+ String name = o.name + (o.argType!=OptionArgType.NONE? " ___" : "");
+ String s = String.format(" %-19s %s", name, o.description);
+ info(s);
+ }
+ }
+
+ public void log(String component, String msg) { logMgr.log(component, msg); }
+ public void log(String msg) { log(null, msg); }
+
+ public int getNumErrors() { return errMgr.getNumErrors(); }
+
+ public void addListener(ANTLRToolListener tl) {
+ if ( tl!=null ) listeners.add(tl);
+ }
+ public void removeListener(ANTLRToolListener tl) { listeners.remove(tl); }
+ public void removeListeners() { listeners.clear(); }
+ public List<ANTLRToolListener> getListeners() { return listeners; }
+
+ public void info(String msg) {
+ if ( listeners.isEmpty() ) {
+ defaultListener.info(msg);
+ return;
+ }
+ for (ANTLRToolListener l : listeners) l.info(msg);
+ }
+ public void error(ANTLRMessage msg) {
+ if ( listeners.isEmpty() ) {
+ defaultListener.error(msg);
+ return;
+ }
+ for (ANTLRToolListener l : listeners) l.error(msg);
+ }
+ public void warning(ANTLRMessage msg) {
+ if ( listeners.isEmpty() ) {
+ defaultListener.warning(msg);
+ }
+ else {
+ for (ANTLRToolListener l : listeners) l.warning(msg);
+ }
+
+ if (warnings_are_errors) {
+ errMgr.emit(ErrorType.WARNING_TREATED_AS_ERROR, new ANTLRMessage(ErrorType.WARNING_TREATED_AS_ERROR));
+ }
+ }
+
+ public void version() {
+ info("ANTLR Parser Generator Version " + VERSION);
+ }
+
+ public void exit(int e) { System.exit(e); }
+
+ public void panic() { throw new Error("ANTLR panic"); }
+
+}
diff --git a/tool/src/org/antlr/v4/analysis/AnalysisPipeline.java b/tool/src/org/antlr/v4/analysis/AnalysisPipeline.java
new file mode 100644
index 0000000..5bd84be
--- /dev/null
+++ b/tool/src/org/antlr/v4/analysis/AnalysisPipeline.java
@@ -0,0 +1,118 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.analysis;
+
+import org.antlr.v4.misc.Utils;
+import org.antlr.v4.runtime.Token;
+import org.antlr.v4.runtime.atn.DecisionState;
+import org.antlr.v4.runtime.atn.LL1Analyzer;
+import org.antlr.v4.runtime.misc.IntervalSet;
+import org.antlr.v4.tool.ErrorType;
+import org.antlr.v4.tool.Grammar;
+import org.antlr.v4.tool.Rule;
+import org.antlr.v4.tool.ast.GrammarAST;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+public class AnalysisPipeline {
+ public Grammar g;
+
+ public AnalysisPipeline(Grammar g) {
+ this.g = g;
+ }
+
+ public void process() {
+ // LEFT-RECURSION CHECK
+ LeftRecursionDetector lr = new LeftRecursionDetector(g, g.atn);
+ lr.check();
+ if ( !lr.listOfRecursiveCycles.isEmpty() ) return; // bail out
+
+ if (g.isLexer()) {
+ processLexer();
+ } else {
+ // BUILD DFA FOR EACH DECISION
+ processParser();
+ }
+ }
+
+ protected void processLexer() {
+ // make sure all non-fragment lexer rules must match at least one symbol
+ for (Rule rule : g.rules.values()) {
+ if (rule.isFragment()) {
+ continue;
+ }
+
+ LL1Analyzer analyzer = new LL1Analyzer(g.atn);
+ IntervalSet look = analyzer.LOOK(g.atn.ruleToStartState[rule.index], null);
+ if (look.contains(Token.EPSILON)) {
+ g.tool.errMgr.grammarError(ErrorType.EPSILON_TOKEN, g.fileName, ((GrammarAST)rule.ast.getChild(0)).getToken(), rule.name);
+ }
+ }
+ }
+
+ protected void processParser() {
+ g.decisionLOOK = new ArrayList<IntervalSet[]>(g.atn.getNumberOfDecisions()+1);
+ for (DecisionState s : g.atn.decisionToState) {
+ g.tool.log("LL1", "\nDECISION "+s.decision+" in rule "+g.getRule(s.ruleIndex).name);
+ IntervalSet[] look;
+ if ( s.nonGreedy ) { // nongreedy decisions can't be LL(1)
+ look = new IntervalSet[s.getNumberOfTransitions()+1];
+ }
+ else {
+ LL1Analyzer anal = new LL1Analyzer(g.atn);
+ look = anal.getDecisionLookahead(s);
+ g.tool.log("LL1", "look=" + Arrays.toString(look));
+ }
+
+ assert s.decision + 1 >= g.decisionLOOK.size();
+ Utils.setSize(g.decisionLOOK, s.decision+1);
+ g.decisionLOOK.set(s.decision, look);
+ g.tool.log("LL1", "LL(1)? " + disjoint(look));
+ }
+ }
+
+ /** Return whether lookahead sets are disjoint; no lookahead => not disjoint */
+ public static boolean disjoint(IntervalSet[] altLook) {
+ boolean collision = false;
+ IntervalSet combined = new IntervalSet();
+ if ( altLook==null ) return false;
+ for (IntervalSet look : altLook) {
+ if ( look==null ) return false; // lookahead must've computation failed
+ if ( !look.and(combined).isNil() ) {
+ collision = true;
+ break;
+ }
+ combined.addAll(look);
+ }
+ return !collision;
+ }
+}
diff --git a/tool/src/org/antlr/v4/analysis/LeftRecursionDetector.java b/tool/src/org/antlr/v4/analysis/LeftRecursionDetector.java
new file mode 100644
index 0000000..44e4b4a
--- /dev/null
+++ b/tool/src/org/antlr/v4/analysis/LeftRecursionDetector.java
@@ -0,0 +1,154 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.analysis;
+
+import org.antlr.v4.runtime.atn.ATN;
+import org.antlr.v4.runtime.atn.ATNState;
+import org.antlr.v4.runtime.atn.RuleStartState;
+import org.antlr.v4.runtime.atn.RuleStopState;
+import org.antlr.v4.runtime.atn.RuleTransition;
+import org.antlr.v4.runtime.atn.Transition;
+import org.antlr.v4.runtime.misc.OrderedHashSet;
+import org.antlr.v4.tool.Grammar;
+import org.antlr.v4.tool.Rule;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class LeftRecursionDetector {
+ Grammar g;
+ public ATN atn;
+
+ /** Holds a list of cycles (sets of rule names). */
+ public List<Set<Rule>> listOfRecursiveCycles = new ArrayList<Set<Rule>>();
+
+ /** Which rule start states have we visited while looking for a single
+ * left-recursion check?
+ */
+ Set<RuleStartState> rulesVisitedPerRuleCheck = new HashSet<RuleStartState>();
+
+ public LeftRecursionDetector(Grammar g, ATN atn) {
+ this.g = g;
+ this.atn = atn;
+ }
+
+ public void check() {
+ for (RuleStartState start : atn.ruleToStartState) {
+ //System.out.print("check "+start.rule.name);
+ rulesVisitedPerRuleCheck.clear();
+ rulesVisitedPerRuleCheck.add(start);
+ //FASerializer ser = new FASerializer(atn.g, start);
+ //System.out.print(":\n"+ser+"\n");
+
+ check(g.getRule(start.ruleIndex), start, new HashSet<ATNState>());
+ }
+ //System.out.println("cycles="+listOfRecursiveCycles);
+ if ( !listOfRecursiveCycles.isEmpty() ) {
+ g.tool.errMgr.leftRecursionCycles(g.fileName, listOfRecursiveCycles);
+ }
+ }
+
+ /** From state s, look for any transition to a rule that is currently
+ * being traced. When tracing r, visitedPerRuleCheck has r
+ * initially. If you reach a rule stop state, return but notify the
+ * invoking rule that the called rule is nullable. This 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.
+ */
+ public boolean check(Rule enclosingRule, ATNState s, Set<ATNState> visitedStates) {
+ if ( s instanceof RuleStopState) return true;
+ if ( visitedStates.contains(s) ) return false;
+ visitedStates.add(s);
+
+ //System.out.println("visit "+s);
+ int n = s.getNumberOfTransitions();
+ boolean stateReachesStopState = false;
+ for (int i=0; i<n; i++) {
+ Transition t = s.transition(i);
+ if ( t instanceof RuleTransition ) {
+ RuleTransition rt = (RuleTransition) t;
+ Rule r = g.getRule(rt.ruleIndex);
+ if ( rulesVisitedPerRuleCheck.contains((RuleStartState)t.target) ) {
+ addRulesToCycle(enclosingRule, r);
+ }
+ else {
+ // must visit if not already visited; mark target, pop when done
+ rulesVisitedPerRuleCheck.add((RuleStartState)t.target);
+ // send new visitedStates set per rule invocation
+ boolean nullable = check(r, t.target, new HashSet<ATNState>());
+ // we're back from visiting that rule
+ rulesVisitedPerRuleCheck.remove((RuleStartState)t.target);
+ if ( nullable ) {
+ stateReachesStopState |= check(enclosingRule, rt.followState, visitedStates);
+ }
+ }
+ }
+ else if ( t.isEpsilon() ) {
+ stateReachesStopState |= check(enclosingRule, t.target, visitedStates);
+ }
+ // else ignore non-epsilon transitions
+ }
+ return stateReachesStopState;
+ }
+
+ /** enclosingRule calls targetRule. 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.
+ */
+ protected void addRulesToCycle(Rule enclosingRule, Rule targetRule) {
+ //System.err.println("left-recursion to "+targetRule.name+" from "+enclosingRule.name);
+ boolean foundCycle = false;
+ for (Set<Rule> rulesInCycle : listOfRecursiveCycles) {
+ // ensure both rules are in same cycle
+ if (rulesInCycle.contains(targetRule)) {
+ rulesInCycle.add(enclosingRule);
+ foundCycle = true;
+ }
+ if (rulesInCycle.contains(enclosingRule)) {
+ rulesInCycle.add(targetRule);
+ foundCycle = true;
+ }
+ }
+ if ( !foundCycle ) {
+ Set<Rule> cycle = new OrderedHashSet<Rule>();
+ cycle.add(targetRule);
+ cycle.add(enclosingRule);
+ listOfRecursiveCycles.add(cycle);
+ }
+ }
+}
diff --git a/tool/src/org/antlr/v4/analysis/LeftRecursiveRuleAltInfo.java b/tool/src/org/antlr/v4/analysis/LeftRecursiveRuleAltInfo.java
new file mode 100644
index 0000000..a5ef7b4
--- /dev/null
+++ b/tool/src/org/antlr/v4/analysis/LeftRecursiveRuleAltInfo.java
@@ -0,0 +1,62 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.analysis;
+
+import org.antlr.v4.tool.ast.AltAST;
+
+public class LeftRecursiveRuleAltInfo {
+ public int altNum; // original alt index (from 1)
+ public String leftRecursiveRuleRefLabel;
+ public String altLabel;
+ public final boolean isListLabel;
+ public String altText;
+ public AltAST altAST; // transformed ALT
+ public AltAST originalAltAST;
+ public int nextPrec;
+
+ public LeftRecursiveRuleAltInfo(int altNum, String altText) {
+ this(altNum, altText, null, null, false, null);
+ }
+
+ public LeftRecursiveRuleAltInfo(int altNum, String altText,
+ String leftRecursiveRuleRefLabel,
+ String altLabel,
+ boolean isListLabel,
+ AltAST originalAltAST)
+ {
+ this.altNum = altNum;
+ this.altText = altText;
+ this.leftRecursiveRuleRefLabel = leftRecursiveRuleRefLabel;
+ this.altLabel = altLabel;
+ this.isListLabel = isListLabel;
+ this.originalAltAST = originalAltAST;
+ }
+}
diff --git a/tool/src/org/antlr/v4/analysis/LeftRecursiveRuleAnalyzer.java b/tool/src/org/antlr/v4/analysis/LeftRecursiveRuleAnalyzer.java
new file mode 100644
index 0000000..5b6ba05
--- /dev/null
+++ b/tool/src/org/antlr/v4/analysis/LeftRecursiveRuleAnalyzer.java
@@ -0,0 +1,446 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.analysis;
+
+import org.antlr.runtime.CommonToken;
+import org.antlr.runtime.Token;
+import org.antlr.runtime.TokenStream;
+import org.antlr.runtime.tree.CommonTreeNodeStream;
+import org.antlr.runtime.tree.Tree;
+import org.antlr.v4.Tool;
+import org.antlr.v4.codegen.CodeGenerator;
+import org.antlr.v4.parse.ANTLRParser;
+import org.antlr.v4.parse.GrammarASTAdaptor;
+import org.antlr.v4.parse.LeftRecursiveRuleWalker;
+import org.antlr.v4.runtime.misc.IntervalSet;
+import org.antlr.v4.runtime.misc.Pair;
+import org.antlr.v4.tool.ErrorType;
+import org.antlr.v4.tool.ast.AltAST;
+import org.antlr.v4.tool.ast.GrammarAST;
+import org.antlr.v4.tool.ast.GrammarASTWithOptions;
+import org.antlr.v4.tool.ast.RuleRefAST;
+import org.stringtemplate.v4.ST;
+import org.stringtemplate.v4.STGroup;
+import org.stringtemplate.v4.STGroupFile;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/** Using a tree walker on the rules, determine if a rule is directly left-recursive and if it follows
+ * our pattern.
+ */
+public class LeftRecursiveRuleAnalyzer extends LeftRecursiveRuleWalker {
+ public static enum ASSOC { left, right }
+
+ public Tool tool;
+ public String ruleName;
+ public LinkedHashMap<Integer, LeftRecursiveRuleAltInfo> binaryAlts = new LinkedHashMap<Integer, LeftRecursiveRuleAltInfo>();
+ public LinkedHashMap<Integer, LeftRecursiveRuleAltInfo> ternaryAlts = new LinkedHashMap<Integer, LeftRecursiveRuleAltInfo>();
+ public LinkedHashMap<Integer, LeftRecursiveRuleAltInfo> suffixAlts = new LinkedHashMap<Integer, LeftRecursiveRuleAltInfo>();
+ public List<LeftRecursiveRuleAltInfo> prefixAlts = new ArrayList<LeftRecursiveRuleAltInfo>();
+ public List<LeftRecursiveRuleAltInfo> otherAlts = new ArrayList<LeftRecursiveRuleAltInfo>();
+
+ /** Pointer to ID node of ^(= ID element) */
+ public List<Pair<GrammarAST,String>> leftRecursiveRuleRefLabels =
+ new ArrayList<Pair<GrammarAST,String>>();
+
+ /** Tokens from which rule AST comes from */
+ public final TokenStream tokenStream;
+
+ public GrammarAST retvals;
+
+ public STGroup recRuleTemplates;
+ public STGroup codegenTemplates;
+ public String language;
+
+ public Map<Integer, ASSOC> altAssociativity = new HashMap<Integer, ASSOC>();
+
+ public LeftRecursiveRuleAnalyzer(GrammarAST ruleAST,
+ Tool tool, String ruleName, String language)
+ {
+ super(new CommonTreeNodeStream(new GrammarASTAdaptor(ruleAST.token.getInputStream()), ruleAST));
+ this.tool = tool;
+ this.ruleName = ruleName;
+ this.language = language;
+ this.tokenStream = ruleAST.g.tokenStream;
+ if (this.tokenStream == null) {
+ throw new NullPointerException("grammar must have a token stream");
+ }
+
+ loadPrecRuleTemplates();
+ }
+
+ public void loadPrecRuleTemplates() {
+ String templateGroupFile = "org/antlr/v4/tool/templates/LeftRecursiveRules.stg";
+ recRuleTemplates = new STGroupFile(templateGroupFile);
+ if ( !recRuleTemplates.isDefined("recRule") ) {
+ tool.errMgr.toolError(ErrorType.MISSING_CODE_GEN_TEMPLATES, "LeftRecursiveRules");
+ }
+
+ // use codegen to get correct language templates; that's it though
+ CodeGenerator gen = new CodeGenerator(tool, null, language);
+ codegenTemplates = gen.getTemplates();
+ }
+
+ @Override
+ public void setReturnValues(GrammarAST t) {
+ retvals = t;
+ }
+
+ @Override
+ public void setAltAssoc(AltAST t, int alt) {
+ ASSOC assoc = ASSOC.left;
+ if ( t.getOptions()!=null ) {
+ String a = t.getOptionString("assoc");
+ if ( a!=null ) {
+ if ( a.equals(ASSOC.right.toString()) ) {
+ assoc = ASSOC.right;
+ }
+ else if ( a.equals(ASSOC.left.toString()) ) {
+ assoc = ASSOC.left;
+ }
+ else {
+ tool.errMgr.grammarError(ErrorType.ILLEGAL_OPTION_VALUE, t.g.fileName, t.getOptionAST("assoc").getToken(), "assoc", assoc);
+ }
+ }
+ }
+
+ if ( altAssociativity.get(alt)!=null && altAssociativity.get(alt)!=assoc ) {
+ tool.errMgr.toolError(ErrorType.INTERNAL_ERROR, "all operators of alt " + alt + " of left-recursive rule must have same associativity");
+ }
+ altAssociativity.put(alt, assoc);
+
+// System.out.println("setAltAssoc: op " + alt + ": " + t.getText()+", assoc="+assoc);
+ }
+
+ @Override
+ public void binaryAlt(AltAST originalAltTree, int alt) {
+ AltAST altTree = (AltAST)originalAltTree.dupTree();
+ String altLabel = altTree.altLabel!=null ? altTree.altLabel.getText() : null;
+
+ String label = null;
+ boolean isListLabel = false;
+ GrammarAST lrlabel = stripLeftRecursion(altTree);
+ if ( lrlabel!=null ) {
+ label = lrlabel.getText();
+ isListLabel = lrlabel.getParent().getType() == PLUS_ASSIGN;
+ leftRecursiveRuleRefLabels.add(new Pair<GrammarAST,String>(lrlabel,altLabel));
+ }
+
+ stripAltLabel(altTree);
+
+ // rewrite e to be e_[rec_arg]
+ int nextPrec = nextPrecedence(alt);
+ altTree = addPrecedenceArgToRules(altTree, nextPrec);
+
+ stripAltLabel(altTree);
+ String altText = text(altTree);
+ altText = altText.trim();
+ LeftRecursiveRuleAltInfo a =
+ new LeftRecursiveRuleAltInfo(alt, altText, label, altLabel, isListLabel, originalAltTree);
+ a.nextPrec = nextPrec;
+ binaryAlts.put(alt, a);
+ //System.out.println("binaryAlt " + alt + ": " + altText + ", rewrite=" + rewriteText);
+ }
+
+ @Override
+ public void prefixAlt(AltAST originalAltTree, int alt) {
+ AltAST altTree = (AltAST)originalAltTree.dupTree();
+ stripAltLabel(altTree);
+
+ int nextPrec = precedence(alt);
+ // rewrite e to be e_[prec]
+ altTree = addPrecedenceArgToRules(altTree, nextPrec);
+ String altText = text(altTree);
+ altText = altText.trim();
+ String altLabel = altTree.altLabel!=null ? altTree.altLabel.getText() : null;
+ LeftRecursiveRuleAltInfo a =
+ new LeftRecursiveRuleAltInfo(alt, altText, null, altLabel, false, originalAltTree);
+ a.nextPrec = nextPrec;
+ prefixAlts.add(a);
+ //System.out.println("prefixAlt " + alt + ": " + altText + ", rewrite=" + rewriteText);
+ }
+
+ @Override
+ public void suffixAlt(AltAST originalAltTree, int alt) {
+ AltAST altTree = (AltAST)originalAltTree.dupTree();
+ String altLabel = altTree.altLabel!=null ? altTree.altLabel.getText() : null;
+
+ String label = null;
+ boolean isListLabel = false;
+ GrammarAST lrlabel = stripLeftRecursion(altTree);
+ if ( lrlabel!=null ) {
+ label = lrlabel.getText();
+ isListLabel = lrlabel.getParent().getType() == PLUS_ASSIGN;
+ leftRecursiveRuleRefLabels.add(new Pair<GrammarAST,String>(lrlabel,altLabel));
+ }
+ stripAltLabel(altTree);
+ String altText = text(altTree);
+ altText = altText.trim();
+ LeftRecursiveRuleAltInfo a =
+ new LeftRecursiveRuleAltInfo(alt, altText, label, altLabel, isListLabel, originalAltTree);
+ suffixAlts.put(alt, a);
+// System.out.println("suffixAlt " + alt + ": " + altText + ", rewrite=" + rewriteText);
+ }
+
+ @Override
+ public void otherAlt(AltAST originalAltTree, int alt) {
+ AltAST altTree = (AltAST)originalAltTree.dupTree();
+ stripAltLabel(altTree);
+ String altText = text(altTree);
+ String altLabel = altTree.altLabel!=null ? altTree.altLabel.getText() : null;
+ LeftRecursiveRuleAltInfo a =
+ new LeftRecursiveRuleAltInfo(alt, altText, null, altLabel, false, originalAltTree);
+ otherAlts.add(a);
+// System.out.println("otherAlt " + alt + ": " + altText);
+ }
+
+ // --------- get transformed rules ----------------
+
+ public String getArtificialOpPrecRule() {
+ ST ruleST = recRuleTemplates.getInstanceOf("recRule");
+ ruleST.add("ruleName", ruleName);
+ ST ruleArgST = codegenTemplates.getInstanceOf("recRuleArg");
+ ruleST.add("argName", ruleArgST);
+ ST setResultST = codegenTemplates.getInstanceOf("recRuleSetResultAction");
+ ruleST.add("setResultAction", setResultST);
+ ruleST.add("userRetvals", retvals);
+
+ LinkedHashMap<Integer, LeftRecursiveRuleAltInfo> opPrecRuleAlts = new LinkedHashMap<Integer, LeftRecursiveRuleAltInfo>();
+ opPrecRuleAlts.putAll(binaryAlts);
+ opPrecRuleAlts.putAll(ternaryAlts);
+ opPrecRuleAlts.putAll(suffixAlts);
+ for (int alt : opPrecRuleAlts.keySet()) {
+ LeftRecursiveRuleAltInfo altInfo = opPrecRuleAlts.get(alt);
+ ST altST = recRuleTemplates.getInstanceOf("recRuleAlt");
+ ST predST = codegenTemplates.getInstanceOf("recRuleAltPredicate");
+ predST.add("opPrec", precedence(alt));
+ predST.add("ruleName", ruleName);
+ altST.add("pred", predST);
+ altST.add("alt", altInfo);
+ altST.add("precOption", LeftRecursiveRuleTransformer.PRECEDENCE_OPTION_NAME);
+ altST.add("opPrec", precedence(alt));
+ ruleST.add("opAlts", altST);
+ }
+
+ ruleST.add("primaryAlts", prefixAlts);
+ ruleST.add("primaryAlts", otherAlts);
+
+ tool.log("left-recursion", ruleST.render());
+
+ return ruleST.render();
+ }
+
+ public AltAST addPrecedenceArgToRules(AltAST t, int prec) {
+ if ( t==null ) return null;
+ // get all top-level rule refs from ALT
+ List<GrammarAST> outerAltRuleRefs = t.getNodesWithTypePreorderDFS(IntervalSet.of(RULE_REF));
+ for (GrammarAST x : outerAltRuleRefs) {
+ RuleRefAST rref = (RuleRefAST)x;
+ boolean recursive = rref.getText().equals(ruleName);
+ boolean rightmost = rref == outerAltRuleRefs.get(outerAltRuleRefs.size()-1);
+ if ( recursive && rightmost ) {
+ GrammarAST dummyValueNode = new GrammarAST(new CommonToken(ANTLRParser.INT, ""+prec));
+ rref.setOption(LeftRecursiveRuleTransformer.PRECEDENCE_OPTION_NAME, dummyValueNode);
+ }
+ }
+ return t;
+ }
+
+ /**
+ * Match (RULE RULE_REF (BLOCK (ALT .*) (ALT RULE_REF[self] .*) (ALT .*)))
+ * Match (RULE RULE_REF (BLOCK (ALT .*) (ALT (ASSIGN ID RULE_REF[self]) .*) (ALT .*)))
+ */
+ public static boolean hasImmediateRecursiveRuleRefs(GrammarAST t, String ruleName) {
+ if ( t==null ) return false;
+ GrammarAST blk = (GrammarAST)t.getFirstChildWithType(BLOCK);
+ if ( blk==null ) return false;
+ int n = blk.getChildren().size();
+ for (int i = 0; i < n; i++) {
+ GrammarAST alt = (GrammarAST)blk.getChildren().get(i);
+ Tree first = alt.getChild(0);
+ if ( first==null ) continue;
+ if (first.getType() == ELEMENT_OPTIONS) {
+ first = alt.getChild(1);
+ if (first == null) {
+ continue;
+ }
+ }
+ if ( first.getType()==RULE_REF && first.getText().equals(ruleName) ) return true;
+ Tree rref = first.getChild(1);
+ if ( rref!=null && rref.getType()==RULE_REF && rref.getText().equals(ruleName) ) return true;
+ }
+ return false;
+ }
+
+ // TODO: this strips the tree properly, but since text()
+ // uses the start of stop token index and gets text from that
+ // ineffectively ignores this routine.
+ public GrammarAST stripLeftRecursion(GrammarAST altAST) {
+ GrammarAST lrlabel=null;
+ GrammarAST first = (GrammarAST)altAST.getChild(0);
+ int leftRecurRuleIndex = 0;
+ if ( first.getType() == ELEMENT_OPTIONS ) {
+ first = (GrammarAST)altAST.getChild(1);
+ leftRecurRuleIndex = 1;
+ }
+ Tree rref = first.getChild(1); // if label=rule
+ if ( (first.getType()==RULE_REF && first.getText().equals(ruleName)) ||
+ (rref!=null && rref.getType()==RULE_REF && rref.getText().equals(ruleName)) )
+ {
+ if ( first.getType()==ASSIGN || first.getType()==PLUS_ASSIGN ) lrlabel = (GrammarAST)first.getChild(0);
+ // remove rule ref (first child unless options present)
+ altAST.deleteChild(leftRecurRuleIndex);
+ // reset index so it prints properly (sets token range of
+ // ALT to start to right of left recur rule we deleted)
+ GrammarAST newFirstChild = (GrammarAST)altAST.getChild(leftRecurRuleIndex);
+ altAST.setTokenStartIndex(newFirstChild.getTokenStartIndex());
+ }
+ return lrlabel;
+ }
+
+ /** Strip last 2 tokens if -> label; alter indexes in altAST */
+ public void stripAltLabel(GrammarAST altAST) {
+ int start = altAST.getTokenStartIndex();
+ int stop = altAST.getTokenStopIndex();
+ // find =>
+ for (int i=stop; i>=start; i--) {
+ if ( tokenStream.get(i).getType()==POUND ) {
+ altAST.setTokenStopIndex(i-1);
+ return;
+ }
+ }
+ }
+
+ public String text(GrammarAST t) {
+ if ( t==null ) return "";
+
+ int tokenStartIndex = t.getTokenStartIndex();
+ int tokenStopIndex = t.getTokenStopIndex();
+
+ // ignore tokens from existing option subtrees like:
+ // (ELEMENT_OPTIONS (= assoc right))
+ //
+ // element options are added back according to the values in the map
+ // returned by getOptions().
+ IntervalSet ignore = new IntervalSet();
+ List<GrammarAST> optionsSubTrees = t.getNodesWithType(ELEMENT_OPTIONS);
+ for (GrammarAST sub : optionsSubTrees) {
+ ignore.add(sub.getTokenStartIndex(), sub.getTokenStopIndex());
+ }
+
+ // Individual labels appear as RULE_REF or TOKEN_REF tokens in the tree,
+ // but do not support the ELEMENT_OPTIONS syntax. Make sure to not try
+ // and add the tokenIndex option when writing these tokens.
+ IntervalSet noOptions = new IntervalSet();
+ List<GrammarAST> labeledSubTrees = t.getNodesWithType(new IntervalSet(ASSIGN,PLUS_ASSIGN));
+ for (GrammarAST sub : labeledSubTrees) {
+ noOptions.add(sub.getChild(0).getTokenStartIndex());
+ }
+
+ StringBuilder buf = new StringBuilder();
+ int i=tokenStartIndex;
+ while ( i<=tokenStopIndex ) {
+ if ( ignore.contains(i) ) {
+ i++;
+ continue;
+ }
+
+ Token tok = tokenStream.get(i);
+
+ // Compute/hold any element options
+ StringBuilder elementOptions = new StringBuilder();
+ if (!noOptions.contains(i)) {
+ GrammarAST node = t.getNodeWithTokenIndex(tok.getTokenIndex());
+ if ( node!=null &&
+ (tok.getType()==TOKEN_REF ||
+ tok.getType()==STRING_LITERAL ||
+ tok.getType()==RULE_REF) )
+ {
+ elementOptions.append("tokenIndex=").append(tok.getTokenIndex());
+ }
+
+ if ( node instanceof GrammarASTWithOptions ) {
+ GrammarASTWithOptions o = (GrammarASTWithOptions)node;
+ for (Map.Entry<String, GrammarAST> entry : o.getOptions().entrySet()) {
+ if (elementOptions.length() > 0) {
+ elementOptions.append(',');
+ }
+
+ elementOptions.append(entry.getKey());
+ elementOptions.append('=');
+ elementOptions.append(entry.getValue().getText());
+ }
+ }
+ }
+
+ buf.append(tok.getText()); // add actual text of the current token to the rewritten alternative
+ i++; // move to the next token
+
+ // Are there args on a rule?
+ if ( tok.getType()==RULE_REF && i<=tokenStopIndex && tokenStream.get(i).getType()==ARG_ACTION ) {
+ buf.append('['+tokenStream.get(i).getText()+']');
+ i++;
+ }
+
+ // now that we have the actual element, we can add the options.
+ if (elementOptions.length() > 0) {
+ buf.append('<').append(elementOptions).append('>');
+ }
+ }
+ return buf.toString();
+ }
+
+ public int precedence(int alt) {
+ return numAlts-alt+1;
+ }
+
+ // Assumes left assoc
+ public int nextPrecedence(int alt) {
+ int p = precedence(alt);
+ if ( altAssociativity.get(alt)==ASSOC.right ) return p;
+ return p+1;
+ }
+
+ @Override
+ public String toString() {
+ return "PrecRuleOperatorCollector{" +
+ "binaryAlts=" + binaryAlts +
+ ", ternaryAlts=" + ternaryAlts +
+ ", suffixAlts=" + suffixAlts +
+ ", prefixAlts=" + prefixAlts +
+ ", otherAlts=" + otherAlts +
+ '}';
+ }
+}
diff --git a/tool/src/org/antlr/v4/analysis/LeftRecursiveRuleTransformer.java b/tool/src/org/antlr/v4/analysis/LeftRecursiveRuleTransformer.java
new file mode 100644
index 0000000..ea67493
--- /dev/null
+++ b/tool/src/org/antlr/v4/analysis/LeftRecursiveRuleTransformer.java
@@ -0,0 +1,276 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.analysis;
+
+import org.antlr.runtime.ANTLRStringStream;
+import org.antlr.runtime.CommonTokenStream;
+import org.antlr.runtime.ParserRuleReturnScope;
+import org.antlr.runtime.RecognitionException;
+import org.antlr.runtime.Token;
+import org.antlr.v4.Tool;
+import org.antlr.v4.misc.OrderedHashMap;
+import org.antlr.v4.parse.ANTLRLexer;
+import org.antlr.v4.parse.ANTLRParser;
+import org.antlr.v4.parse.GrammarASTAdaptor;
+import org.antlr.v4.parse.ScopeParser;
+import org.antlr.v4.parse.ToolANTLRParser;
+import org.antlr.v4.runtime.misc.Pair;
+import org.antlr.v4.semantics.BasicSemanticChecks;
+import org.antlr.v4.semantics.RuleCollector;
+import org.antlr.v4.tool.AttributeDict;
+import org.antlr.v4.tool.ErrorType;
+import org.antlr.v4.tool.Grammar;
+import org.antlr.v4.tool.GrammarTransformPipeline;
+import org.antlr.v4.tool.LabelElementPair;
+import org.antlr.v4.tool.LeftRecursiveRule;
+import org.antlr.v4.tool.Rule;
+import org.antlr.v4.tool.ast.ActionAST;
+import org.antlr.v4.tool.ast.AltAST;
+import org.antlr.v4.tool.ast.BlockAST;
+import org.antlr.v4.tool.ast.GrammarAST;
+import org.antlr.v4.tool.ast.GrammarASTWithOptions;
+import org.antlr.v4.tool.ast.GrammarRootAST;
+import org.antlr.v4.tool.ast.RuleAST;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/** Remove left-recursive rule refs, add precedence args to recursive rule refs.
+ * Rewrite rule so we can create ATN.
+ *
+ * MODIFIES grammar AST in place.
+ */
+public class LeftRecursiveRuleTransformer {
+ public static final String PRECEDENCE_OPTION_NAME = "p";
+ public static final String TOKENINDEX_OPTION_NAME = "tokenIndex";
+
+ public GrammarRootAST ast;
+ public Collection<Rule> rules;
+ public Grammar g;
+ public Tool tool;
+
+ public LeftRecursiveRuleTransformer(GrammarRootAST ast, Collection<Rule> rules, Grammar g) {
+ this.ast = ast;
+ this.rules = rules;
+ this.g = g;
+ this.tool = g.tool;
+ }
+
+ public void translateLeftRecursiveRules() {
+ String language = g.getOptionString("language");
+ // translate all recursive rules
+ List<String> leftRecursiveRuleNames = new ArrayList<String>();
+ for (Rule r : rules) {
+ if ( !Grammar.isTokenName(r.name) ) {
+ if ( LeftRecursiveRuleAnalyzer.hasImmediateRecursiveRuleRefs(r.ast, r.name) ) {
+ boolean fitsPattern = translateLeftRecursiveRule(ast, (LeftRecursiveRule)r, language);
+ if ( fitsPattern ) {
+ leftRecursiveRuleNames.add(r.name);
+ }
+ else { // better given an error that non-conforming left-recursion exists
+ tool.errMgr.grammarError(ErrorType.NONCONFORMING_LR_RULE, g.fileName, ((GrammarAST)r.ast.getChild(0)).token, r.name);
+ }
+ }
+ }
+ }
+
+ // update all refs to recursive rules to have [0] argument
+ for (GrammarAST r : ast.getNodesWithType(ANTLRParser.RULE_REF)) {
+ if ( r.getParent().getType()==ANTLRParser.RULE ) continue; // must be rule def
+ if ( ((GrammarASTWithOptions)r).getOptionString(PRECEDENCE_OPTION_NAME) != null ) continue; // already has arg; must be in rewritten rule
+ if ( leftRecursiveRuleNames.contains(r.getText()) ) {
+ // found ref to recursive rule not already rewritten with arg
+ ((GrammarASTWithOptions)r).setOption(PRECEDENCE_OPTION_NAME, (GrammarAST)new GrammarASTAdaptor().create(ANTLRParser.INT, "0"));
+ }
+ }
+ }
+
+ /** Return true if successful */
+ public boolean translateLeftRecursiveRule(GrammarRootAST ast,
+ LeftRecursiveRule r,
+ String language)
+ {
+ //tool.log("grammar", ruleAST.toStringTree());
+ GrammarAST prevRuleAST = r.ast;
+ String ruleName = prevRuleAST.getChild(0).getText();
+ LeftRecursiveRuleAnalyzer leftRecursiveRuleWalker =
+ new LeftRecursiveRuleAnalyzer(prevRuleAST, tool, ruleName, language);
+ boolean isLeftRec;
+ try {
+// System.out.println("TESTING ---------------\n"+
+// leftRecursiveRuleWalker.text(ruleAST));
+ isLeftRec = leftRecursiveRuleWalker.rec_rule();
+ }
+ catch (RecognitionException re) {
+ isLeftRec = false; // didn't match; oh well
+ }
+ if ( !isLeftRec ) return false;
+
+ // replace old rule's AST; first create text of altered rule
+ GrammarAST RULES = (GrammarAST)ast.getFirstChildWithType(ANTLRParser.RULES);
+ String newRuleText = leftRecursiveRuleWalker.getArtificialOpPrecRule();
+// System.out.println("created: "+newRuleText);
+ // now parse within the context of the grammar that originally created
+ // the AST we are transforming. This could be an imported grammar so
+ // we cannot just reference this.g because the role might come from
+ // the imported grammar and not the root grammar (this.g)
+ RuleAST t = parseArtificialRule(prevRuleAST.g, newRuleText);
+
+ // reuse the name token from the original AST since it refers to the proper source location in the original grammar
+ ((GrammarAST)t.getChild(0)).token = ((GrammarAST)prevRuleAST.getChild(0)).getToken();
+
+ // update grammar AST and set rule's AST.
+ RULES.setChild(prevRuleAST.getChildIndex(), t);
+ r.ast = t;
+
+ // Reduce sets in newly created rule tree
+ GrammarTransformPipeline transform = new GrammarTransformPipeline(g, g.tool);
+ transform.reduceBlocksToSets(r.ast);
+ transform.expandParameterizedLoops(r.ast);
+
+ // Rerun semantic checks on the new rule
+ RuleCollector ruleCollector = new RuleCollector(g);
+ ruleCollector.visit(t, "rule");
+ BasicSemanticChecks basics = new BasicSemanticChecks(g, ruleCollector);
+ // disable the assoc element option checks because they are already
+ // handled for the pre-transformed rule.
+ basics.checkAssocElementOption = false;
+ basics.visit(t, "rule");
+
+ // track recursive alt info for codegen
+ r.recPrimaryAlts = new ArrayList<LeftRecursiveRuleAltInfo>();
+ r.recPrimaryAlts.addAll(leftRecursiveRuleWalker.prefixAlts);
+ r.recPrimaryAlts.addAll(leftRecursiveRuleWalker.otherAlts);
+ if (r.recPrimaryAlts.isEmpty()) {
+ tool.errMgr.grammarError(ErrorType.NO_NON_LR_ALTS, g.fileName, ((GrammarAST)r.ast.getChild(0)).getToken(), r.name);
+ }
+
+ r.recOpAlts = new OrderedHashMap<Integer, LeftRecursiveRuleAltInfo>();
+ r.recOpAlts.putAll(leftRecursiveRuleWalker.binaryAlts);
+ r.recOpAlts.putAll(leftRecursiveRuleWalker.ternaryAlts);
+ r.recOpAlts.putAll(leftRecursiveRuleWalker.suffixAlts);
+
+ // walk alt info records and set their altAST to point to appropriate ALT subtree
+ // from freshly created AST
+ setAltASTPointers(r, t);
+
+ // update Rule to just one alt and add prec alt
+ ActionAST arg = (ActionAST)r.ast.getFirstChildWithType(ANTLRParser.ARG_ACTION);
+ if ( arg!=null ) {
+ r.args = ScopeParser.parseTypedArgList(arg, arg.getText(), g);
+ r.args.type = AttributeDict.DictType.ARG;
+ r.args.ast = arg;
+ arg.resolver = r.alt[1]; // todo: isn't this Rule or something?
+ }
+
+ // define labels on recursive rule refs we delete; they don't point to nodes of course
+ // these are so $label in action translation works
+ for (Pair<GrammarAST,String> pair : leftRecursiveRuleWalker.leftRecursiveRuleRefLabels) {
+ GrammarAST labelNode = pair.a;
+ GrammarAST labelOpNode = (GrammarAST)labelNode.getParent();
+ GrammarAST elementNode = (GrammarAST)labelOpNode.getChild(1);
+ LabelElementPair lp = new LabelElementPair(g, labelNode, elementNode, labelOpNode.getType());
+ r.alt[1].labelDefs.map(labelNode.getText(), lp);
+ }
+ // copy to rule from walker
+ r.leftRecursiveRuleRefLabels = leftRecursiveRuleWalker.leftRecursiveRuleRefLabels;
+
+ tool.log("grammar", "added: "+t.toStringTree());
+ return true;
+ }
+
+ public RuleAST parseArtificialRule(final Grammar g, String ruleText) {
+ ANTLRLexer lexer = new ANTLRLexer(new ANTLRStringStream(ruleText));
+ GrammarASTAdaptor adaptor = new GrammarASTAdaptor(lexer.getCharStream());
+ CommonTokenStream tokens = new CommonTokenStream(lexer);
+ lexer.tokens = tokens;
+ ToolANTLRParser p = new ToolANTLRParser(tokens, tool);
+ p.setTreeAdaptor(adaptor);
+ Token ruleStart = null;
+ try {
+ ParserRuleReturnScope r = p.rule();
+ RuleAST tree = (RuleAST)r.getTree();
+ ruleStart = (Token)r.getStart();
+ GrammarTransformPipeline.setGrammarPtr(g, tree);
+ GrammarTransformPipeline.augmentTokensWithOriginalPosition(g, tree);
+ return tree;
+ }
+ catch (Exception e) {
+ tool.errMgr.toolError(ErrorType.INTERNAL_ERROR,
+ e,
+ ruleStart,
+ "error parsing rule created during left-recursion detection: "+ruleText);
+ }
+ return null;
+ }
+
+ /**
+ * <pre>
+ * (RULE e int _p (returns int v)
+ * (BLOCK
+ * (ALT
+ * (BLOCK
+ * (ALT INT {$v = $INT.int;})
+ * (ALT '(' (= x e) ')' {$v = $x.v;})
+ * (ALT ID))
+ * (* (BLOCK
+ * (OPTIONS ...)
+ * (ALT {7 >= $_p}? '*' (= b e) {$v = $a.v * $b.v;})
+ * (ALT {6 >= $_p}? '+' (= b e) {$v = $a.v + $b.v;})
+ * (ALT {3 >= $_p}? '++') (ALT {2 >= $_p}? '--'))))))
+ * </pre>
+ */
+ public void setAltASTPointers(LeftRecursiveRule r, RuleAST t) {
+// System.out.println("RULE: "+t.toStringTree());
+ BlockAST ruleBlk = (BlockAST)t.getFirstChildWithType(ANTLRParser.BLOCK);
+ AltAST mainAlt = (AltAST)ruleBlk.getChild(0);
+ BlockAST primaryBlk = (BlockAST)mainAlt.getChild(0);
+ BlockAST opsBlk = (BlockAST)mainAlt.getChild(1).getChild(0); // (* BLOCK ...)
+ for (int i = 0; i < r.recPrimaryAlts.size(); i++) {
+ LeftRecursiveRuleAltInfo altInfo = r.recPrimaryAlts.get(i);
+ altInfo.altAST = (AltAST)primaryBlk.getChild(i);
+ altInfo.altAST.leftRecursiveAltInfo = altInfo;
+ altInfo.originalAltAST.leftRecursiveAltInfo = altInfo;
+// altInfo.originalAltAST.parent = altInfo.altAST.parent;
+// System.out.println(altInfo.altAST.toStringTree());
+ }
+ for (int i = 0; i < r.recOpAlts.size(); i++) {
+ LeftRecursiveRuleAltInfo altInfo = r.recOpAlts.getElement(i);
+ altInfo.altAST = (AltAST)opsBlk.getChild(i);
+ altInfo.altAST.leftRecursiveAltInfo = altInfo;
+ altInfo.originalAltAST.leftRecursiveAltInfo = altInfo;
+// altInfo.originalAltAST.parent = altInfo.altAST.parent;
+// System.out.println(altInfo.altAST.toStringTree());
+ }
+ }
+
+}
diff --git a/tool/src/org/antlr/v4/automata/ATNFactory.java b/tool/src/org/antlr/v4/automata/ATNFactory.java
new file mode 100644
index 0000000..aff2862
--- /dev/null
+++ b/tool/src/org/antlr/v4/automata/ATNFactory.java
@@ -0,0 +1,244 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.automata;
+
+import org.antlr.v4.runtime.atn.ATN;
+import org.antlr.v4.runtime.atn.ATNState;
+import org.antlr.v4.tool.ast.ActionAST;
+import org.antlr.v4.tool.ast.BlockAST;
+import org.antlr.v4.tool.ast.GrammarAST;
+import org.antlr.v4.tool.ast.PredAST;
+import org.antlr.v4.tool.ast.TerminalAST;
+
+import java.util.List;
+
+public interface ATNFactory {
+ /** A pair of states pointing to the left/right (start and end) states of a
+ * state submachine. Used to build ATNs.
+ */
+ public static class Handle {
+ public ATNState left;
+ public ATNState right;
+
+ public Handle(ATNState left, ATNState right) {
+ this.left = left;
+ this.right = right;
+ }
+
+ @Override
+ public String toString() {
+ return "("+left+","+right+")";
+ }
+ }
+
+
+ ATN createATN();
+
+ void setCurrentRuleName(String name);
+
+ void setCurrentOuterAlt(int alt);
+
+
+ Handle rule(GrammarAST ruleAST, String name, Handle blk);
+
+
+ ATNState newState();
+
+
+ Handle label(Handle t);
+
+
+ Handle listLabel(Handle t);
+
+
+ Handle tokenRef(TerminalAST node);
+
+
+ Handle set(GrammarAST associatedAST, List<GrammarAST> alts, boolean invert);
+
+
+ Handle charSetLiteral(GrammarAST charSetAST);
+
+
+ Handle range(GrammarAST a, GrammarAST b);
+
+ /** For a non-lexer, just build a simple token reference atom.
+ * For a lexer, a string is a sequence of char to match. That is,
+ * "fog" is treated as 'f' 'o' 'g' not as a single transition in
+ * the DFA. Machine== o-'f'->o-'o'->o-'g'->o and has n+1 states
+ * for n characters.
+ */
+
+ Handle stringLiteral(TerminalAST stringLiteralAST);
+
+ /** For reference to rule r, build
+ *
+ * o-e->(r) o
+ *
+ * where (r) is the start of rule r and the trailing o is not linked
+ * to from rule ref state directly (it's done thru the transition(0)
+ * RuleClosureTransition.
+ *
+ * If the rule r is just a list of tokens, it's block will be just
+ * a set on an edge o->o->o-set->o->o->o, could inline it rather than doing
+ * the rule reference, but i'm not doing this yet as I'm not sure
+ * it would help much in the ATN->DFA construction.
+ *
+ * TODO add to codegen: collapse alt blks that are sets into single matchSet
+ * @param node
+ */
+
+ Handle ruleRef(GrammarAST node);
+
+ /** From an empty alternative build Grip o-e->o */
+
+ Handle epsilon(GrammarAST node);
+
+ /** Build what amounts to an epsilon transition with a semantic
+ * predicate action. The pred is a pointer into the AST of
+ * the SEMPRED token.
+ */
+
+ Handle sempred(PredAST pred);
+
+ /** Build what amounts to an epsilon transition with an action.
+ * The action goes into ATN though it is ignored during analysis.
+ */
+
+ Handle action(ActionAST action);
+
+
+ Handle action(String action);
+
+
+ Handle alt(List<Handle> els);
+
+ /** From A|B|..|Z alternative block build
+ *
+ * o->o-A->o->o (last ATNState is blockEndATNState pointed to by all alts)
+ * | ^
+ * o->o-B->o--|
+ * | |
+ * ... |
+ * | |
+ * o->o-Z->o--|
+ *
+ * So every alternative gets begin ATNState connected by epsilon
+ * and every alt right side points at a block end ATNState. There is a
+ * new ATNState in the ATNState in the Grip for each alt plus one for the
+ * end ATNState.
+ *
+ * Special case: only one alternative: don't make a block with alt
+ * begin/end.
+ *
+ * Special case: if just a list of tokens/chars/sets, then collapse
+ * to a single edge'd o-set->o graph.
+ *
+ * Set alt number (1..n) in the left-Transition ATNState.
+ */
+
+ Handle block(BlockAST blockAST, GrammarAST ebnfRoot, List<Handle> alternativeGrips);
+
+// Handle notBlock(GrammarAST blockAST, Handle set);
+
+ /** From (A)? build either:
+ *
+ * o--A->o
+ * | ^
+ * o---->|
+ *
+ * or, if A is a block, just add an empty alt to the end of the block
+ */
+
+ Handle optional(GrammarAST optAST, Handle blk);
+
+ /** From (A)+ build
+ *
+ * |---| (Transition 2 from A.right points at alt 1)
+ * v | (follow of loop is Transition 1)
+ * o->o-A-o->o
+ *
+ * Meaning that the last ATNState in A points back to A's left Transition ATNState
+ * and we add a new begin/end ATNState. A can be single alternative or
+ * multiple.
+ *
+ * During analysis we'll call the follow link (transition 1) alt n+1 for
+ * an n-alt A block.
+ */
+
+ Handle plus(GrammarAST plusAST, Handle blk);
+
+ /** From (A)* build
+ *
+ * |---|
+ * v |
+ * o->o-A-o--o (Transition 2 from block end points at alt 1; follow is Transition 1)
+ * | ^
+ * o---------| (optional branch is 2nd alt of optional block containing A+)
+ *
+ * Meaning that the last (end) ATNState in A points back to A's
+ * left side ATNState and we add 3 new ATNStates (the
+ * optional branch is built just like an optional subrule).
+ * See the Aplus() method for more on the loop back Transition.
+ * The new node on right edge is set to RIGHT_EDGE_OF_CLOSURE so we
+ * can detect nested (A*)* loops and insert an extra node. Previously,
+ * two blocks shared same EOB node.
+ *
+ * There are 2 or 3 decision points in a A*. If A is not a block (i.e.,
+ * it only has one alt), then there are two decisions: the optional bypass
+ * and then loopback. If A is a block of alts, then there are three
+ * decisions: bypass, loopback, and A's decision point.
+ *
+ * Note that the optional bypass must be outside the loop as (A|B)* is
+ * not the same thing as (A|B|)+.
+ *
+ * This is an accurate ATN representation of the meaning of (A)*, but
+ * for generating code, I don't need a DFA for the optional branch by
+ * virtue of how I generate code. The exit-loopback-branch decision
+ * is sufficient to let me make an appropriate enter, exit, loop
+ * determination. See codegen.g
+ */
+
+ Handle star(GrammarAST starAST, Handle blk);
+
+ /** Build an atom with all possible values in its label */
+
+ Handle wildcard(GrammarAST associatedAST);
+
+
+ Handle lexerAltCommands(Handle alt, Handle cmds);
+
+
+ Handle lexerCallCommand(GrammarAST ID, GrammarAST arg);
+
+
+ Handle lexerCommand(GrammarAST ID);
+}
diff --git a/tool/src/org/antlr/v4/automata/ATNOptimizer.java b/tool/src/org/antlr/v4/automata/ATNOptimizer.java
new file mode 100644
index 0000000..4f72b64
--- /dev/null
+++ b/tool/src/org/antlr/v4/automata/ATNOptimizer.java
@@ -0,0 +1,170 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.automata;
+
+import org.antlr.v4.runtime.atn.ATN;
+import org.antlr.v4.runtime.atn.ATNState;
+import org.antlr.v4.runtime.atn.AtomTransition;
+import org.antlr.v4.runtime.atn.BlockEndState;
+import org.antlr.v4.runtime.atn.DecisionState;
+import org.antlr.v4.runtime.atn.EpsilonTransition;
+import org.antlr.v4.runtime.atn.NotSetTransition;
+import org.antlr.v4.runtime.atn.RangeTransition;
+import org.antlr.v4.runtime.atn.SetTransition;
+import org.antlr.v4.runtime.atn.Transition;
+import org.antlr.v4.runtime.misc.Interval;
+import org.antlr.v4.runtime.misc.IntervalSet;
+import org.antlr.v4.tool.Grammar;
+import org.antlr.v4.tool.Rule;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ *
+ * @author Sam Harwell
+ */
+public class ATNOptimizer {
+
+ public static void optimize(Grammar g, ATN atn) {
+ optimizeSets(g, atn);
+ optimizeStates(atn);
+ }
+
+ private static void optimizeSets(Grammar g, ATN atn) {
+ if (g.isParser()) {
+ // parser codegen doesn't currently support SetTransition
+ return;
+ }
+
+ int removedStates = 0;
+ List<DecisionState> decisions = atn.decisionToState;
+ for (DecisionState decision : decisions) {
+ if (decision.ruleIndex >= 0) {
+ Rule rule = g.getRule(decision.ruleIndex);
+ if (Character.isLowerCase(rule.name.charAt(0))) {
+ // parser codegen doesn't currently support SetTransition
+ continue;
+ }
+ }
+
+ IntervalSet setTransitions = new IntervalSet();
+ for (int i = 0; i < decision.getNumberOfTransitions(); i++) {
+ Transition epsTransition = decision.transition(i);
+ if (!(epsTransition instanceof EpsilonTransition)) {
+ continue;
+ }
+
+ if (epsTransition.target.getNumberOfTransitions() != 1) {
+ continue;
+ }
+
+ Transition transition = epsTransition.target.transition(0);
+ if (!(transition.target instanceof BlockEndState)) {
+ continue;
+ }
+
+ if (transition instanceof NotSetTransition) {
+ // TODO: not yet implemented
+ continue;
+ }
+
+ if (transition instanceof AtomTransition
+ || transition instanceof RangeTransition
+ || transition instanceof SetTransition)
+ {
+ setTransitions.add(i);
+ }
+ }
+
+ // due to min alt resolution policies, can only collapse sequential alts
+ for (int i = setTransitions.getIntervals().size() - 1; i >= 0; i--) {
+ Interval interval = setTransitions.getIntervals().get(i);
+ if (interval.length() <= 1) {
+ continue;
+ }
+
+ ATNState blockEndState = decision.transition(interval.a).target.transition(0).target;
+ IntervalSet matchSet = new IntervalSet();
+ for (int j = interval.a; j <= interval.b; j++) {
+ Transition matchTransition = decision.transition(j).target.transition(0);
+ if (matchTransition instanceof NotSetTransition) {
+ throw new UnsupportedOperationException("Not yet implemented.");
+ } else {
+ matchSet.addAll(matchTransition.label());
+ }
+ }
+
+ Transition newTransition;
+ if (matchSet.getIntervals().size() == 1) {
+ if (matchSet.size() == 1) {
+ newTransition = new AtomTransition(blockEndState, matchSet.getMinElement());
+ } else {
+ Interval matchInterval = matchSet.getIntervals().get(0);
+ newTransition = new RangeTransition(blockEndState, matchInterval.a, matchInterval.b);
+ }
+ } else {
+ newTransition = new SetTransition(blockEndState, matchSet);
+ }
+
+ decision.transition(interval.a).target.setTransition(0, newTransition);
+ for (int j = interval.a + 1; j <= interval.b; j++) {
+ Transition removed = decision.removeTransition(interval.a + 1);
+ atn.removeState(removed.target);
+ removedStates++;
+ }
+ }
+ }
+
+// System.out.println("ATN optimizer removed " + removedStates + " states by collapsing sets.");
+ }
+
+ private static void optimizeStates(ATN atn) {
+// System.out.println(atn.states);
+ List<ATNState> compressed = new ArrayList<ATNState>();
+ int i = 0; // new state number
+ for (ATNState s : atn.states) {
+ if ( s!=null ) {
+ compressed.add(s);
+ s.stateNumber = i; // reset state number as we shift to new position
+ i++;
+ }
+ }
+// System.out.println(compressed);
+// System.out.println("ATN optimizer removed " + (atn.states.size() - compressed.size()) + " null states.");
+ atn.states.clear();
+ atn.states.addAll(compressed);
+ }
+
+ private ATNOptimizer() {
+ }
+
+}
diff --git a/tool/src/org/antlr/v4/automata/ATNPrinter.java b/tool/src/org/antlr/v4/automata/ATNPrinter.java
new file mode 100644
index 0000000..9fe1145
--- /dev/null
+++ b/tool/src/org/antlr/v4/automata/ATNPrinter.java
@@ -0,0 +1,139 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.automata;
+
+import org.antlr.v4.runtime.atn.ATNState;
+import org.antlr.v4.runtime.atn.ActionTransition;
+import org.antlr.v4.runtime.atn.AtomTransition;
+import org.antlr.v4.runtime.atn.BlockEndState;
+import org.antlr.v4.runtime.atn.BlockStartState;
+import org.antlr.v4.runtime.atn.EpsilonTransition;
+import org.antlr.v4.runtime.atn.NotSetTransition;
+import org.antlr.v4.runtime.atn.PlusBlockStartState;
+import org.antlr.v4.runtime.atn.PlusLoopbackState;
+import org.antlr.v4.runtime.atn.RuleStartState;
+import org.antlr.v4.runtime.atn.RuleStopState;
+import org.antlr.v4.runtime.atn.RuleTransition;
+import org.antlr.v4.runtime.atn.SetTransition;
+import org.antlr.v4.runtime.atn.StarBlockStartState;
+import org.antlr.v4.runtime.atn.StarLoopEntryState;
+import org.antlr.v4.runtime.atn.StarLoopbackState;
+import org.antlr.v4.runtime.atn.Transition;
+import org.antlr.v4.tool.Grammar;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/** An ATN walker that knows how to dump them to serialized strings. */
+public class ATNPrinter {
+ List<ATNState> work;
+ Set<ATNState> marked;
+ Grammar g;
+ ATNState start;
+
+ public ATNPrinter(Grammar g, ATNState start) {
+ this.g = g;
+ this.start = start;
+ }
+
+ public String asString() {
+ if ( start==null ) return null;
+ marked = new HashSet<ATNState>();
+
+ work = new ArrayList<ATNState>();
+ work.add(start);
+
+ StringBuilder buf = new StringBuilder();
+ ATNState s;
+
+ while ( !work.isEmpty() ) {
+ s = work.remove(0);
+ if ( marked.contains(s) ) continue;
+ int n = s.getNumberOfTransitions();
+// System.out.println("visit "+s+"; edges="+n);
+ marked.add(s);
+ for (int i=0; i<n; i++) {
+ Transition t = s.transition(i);
+ if ( !(s instanceof RuleStopState) ) { // don't add follow states to work
+ if ( t instanceof RuleTransition ) work.add(((RuleTransition)t).followState);
+ else work.add( t.target );
+ }
+ buf.append(getStateString(s));
+ if ( t instanceof EpsilonTransition ) {
+ buf.append("->").append(getStateString(t.target)).append('\n');
+ }
+ else if ( t instanceof RuleTransition ) {
+ buf.append("-").append(g.getRule(((RuleTransition)t).ruleIndex).name).append("->").append(getStateString(t.target)).append('\n');
+ }
+ else if ( t instanceof ActionTransition ) {
+ ActionTransition a = (ActionTransition)t;
+ buf.append("-").append(a.toString()).append("->").append(getStateString(t.target)).append('\n');
+ }
+ else if ( t instanceof SetTransition ) {
+ SetTransition st = (SetTransition)t;
+ boolean not = st instanceof NotSetTransition;
+ if ( g.isLexer() ) {
+ buf.append("-").append(not?"~":"").append(st.toString()).append("->").append(getStateString(t.target)).append('\n');
+ }
+ else {
+ buf.append("-").append(not?"~":"").append(st.label().toString(g.getVocabulary())).append("->").append(getStateString(t.target)).append('\n');
+ }
+ }
+ else if ( t instanceof AtomTransition ) {
+ AtomTransition a = (AtomTransition)t;
+ String label = g.getTokenDisplayName(a.label);
+ buf.append("-").append(label).append("->").append(getStateString(t.target)).append('\n');
+ }
+ else {
+ buf.append("-").append(t.toString()).append("->").append(getStateString(t.target)).append('\n');
+ }
+ }
+ }
+ return buf.toString();
+ }
+
+ String getStateString(ATNState s) {
+ int n = s.stateNumber;
+ String stateStr = "s"+n;
+ if ( s instanceof StarBlockStartState ) stateStr = "StarBlockStart_"+n;
+ else if ( s instanceof PlusBlockStartState ) stateStr = "PlusBlockStart_"+n;
+ else if ( s instanceof BlockStartState) stateStr = "BlockStart_"+n;
+ else if ( s instanceof BlockEndState ) stateStr = "BlockEnd_"+n;
+ else if ( s instanceof RuleStartState) stateStr = "RuleStart_"+g.getRule(s.ruleIndex).name+"_"+n;
+ else if ( s instanceof RuleStopState ) stateStr = "RuleStop_"+g.getRule(s.ruleIndex).name+"_"+n;
+ else if ( s instanceof PlusLoopbackState) stateStr = "PlusLoopBack_"+n;
+ else if ( s instanceof StarLoopbackState) stateStr = "StarLoopBack_"+n;
+ else if ( s instanceof StarLoopEntryState) stateStr = "StarLoopEntry_"+n;
+ return stateStr;
+ }
+}
diff --git a/tool/src/org/antlr/v4/automata/ATNVisitor.java b/tool/src/org/antlr/v4/automata/ATNVisitor.java
new file mode 100644
index 0000000..af5e18a
--- /dev/null
+++ b/tool/src/org/antlr/v4/automata/ATNVisitor.java
@@ -0,0 +1,61 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.automata;
+
+import org.antlr.v4.runtime.atn.ATNState;
+import org.antlr.v4.runtime.atn.Transition;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/** A simple visitor that walks everywhere it can go starting from s,
+ * without going into an infinite cycle. Override and implement
+ * visitState() to provide functionality.
+ */
+public class ATNVisitor {
+ public void visit(ATNState s) {
+ visit_(s, new HashSet<Integer>());
+ }
+
+ public void visit_(ATNState s, Set<Integer> visited) {
+ if ( !visited.add(s.stateNumber) ) return;
+ visited.add(s.stateNumber);
+
+ visitState(s);
+ int n = s.getNumberOfTransitions();
+ for (int i=0; i<n; i++) {
+ Transition t = s.transition(i);
+ visit_(t.target, visited);
+ }
+ }
+
+ public void visitState(ATNState s) { }
+}
diff --git a/tool/src/org/antlr/v4/automata/LexerATNFactory.java b/tool/src/org/antlr/v4/automata/LexerATNFactory.java
new file mode 100644
index 0000000..4feff0a
--- /dev/null
+++ b/tool/src/org/antlr/v4/automata/LexerATNFactory.java
@@ -0,0 +1,483 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.automata;
+
+import org.antlr.runtime.CommonToken;
+import org.antlr.runtime.Token;
+import org.antlr.v4.codegen.CodeGenerator;
+import org.antlr.v4.misc.CharSupport;
+import org.antlr.v4.parse.ANTLRParser;
+import org.antlr.v4.runtime.IntStream;
+import org.antlr.v4.runtime.Lexer;
+import org.antlr.v4.runtime.atn.ATN;
+import org.antlr.v4.runtime.atn.ATNState;
+import org.antlr.v4.runtime.atn.ActionTransition;
+import org.antlr.v4.runtime.atn.AtomTransition;
+import org.antlr.v4.runtime.atn.LexerAction;
+import org.antlr.v4.runtime.atn.LexerChannelAction;
+import org.antlr.v4.runtime.atn.LexerCustomAction;
+import org.antlr.v4.runtime.atn.LexerModeAction;
+import org.antlr.v4.runtime.atn.LexerMoreAction;
+import org.antlr.v4.runtime.atn.LexerPopModeAction;
+import org.antlr.v4.runtime.atn.LexerPushModeAction;
+import org.antlr.v4.runtime.atn.LexerSkipAction;
+import org.antlr.v4.runtime.atn.LexerTypeAction;
+import org.antlr.v4.runtime.atn.NotSetTransition;
+import org.antlr.v4.runtime.atn.RangeTransition;
+import org.antlr.v4.runtime.atn.RuleStartState;
+import org.antlr.v4.runtime.atn.SetTransition;
+import org.antlr.v4.runtime.atn.TokensStartState;
+import org.antlr.v4.runtime.atn.Transition;
+import org.antlr.v4.runtime.misc.Interval;
+import org.antlr.v4.runtime.misc.IntervalSet;
+import org.antlr.v4.tool.ErrorType;
+import org.antlr.v4.tool.LexerGrammar;
+import org.antlr.v4.tool.Rule;
+import org.antlr.v4.tool.ast.ActionAST;
+import org.antlr.v4.tool.ast.GrammarAST;
+import org.antlr.v4.tool.ast.TerminalAST;
+import org.stringtemplate.v4.ST;
+import org.stringtemplate.v4.STGroup;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class LexerATNFactory extends ParserATNFactory {
+ public STGroup codegenTemplates;
+
+ /**
+ * Provides a map of names of predefined constants which are likely to
+ * appear as the argument for lexer commands. These names would be resolved
+ * by the Java compiler for lexer commands that are translated to embedded
+ * actions, but are required during code generation for creating
+ * {@link LexerAction} instances that are usable by a lexer interpreter.
+ */
+ protected static final Map<String, Integer> COMMON_CONSTANTS = new HashMap<String, Integer>();
+ static {
+ COMMON_CONSTANTS.put("HIDDEN", Lexer.HIDDEN);
+ COMMON_CONSTANTS.put("DEFAULT_TOKEN_CHANNEL", Lexer.DEFAULT_TOKEN_CHANNEL);
+ COMMON_CONSTANTS.put("DEFAULT_MODE", Lexer.DEFAULT_MODE);
+ COMMON_CONSTANTS.put("SKIP", Lexer.SKIP);
+ COMMON_CONSTANTS.put("MORE", Lexer.MORE);
+ COMMON_CONSTANTS.put("EOF", Lexer.EOF);
+ COMMON_CONSTANTS.put("MAX_CHAR_VALUE", Lexer.MAX_CHAR_VALUE);
+ COMMON_CONSTANTS.put("MIN_CHAR_VALUE", Lexer.MIN_CHAR_VALUE);
+ }
+
+ /**
+ * Maps from an action index to a {@link LexerAction} object.
+ */
+ protected Map<Integer, LexerAction> indexToActionMap = new HashMap<Integer, LexerAction>();
+ /**
+ * Maps from a {@link LexerAction} object to the action index.
+ */
+ protected Map<LexerAction, Integer> actionToIndexMap = new HashMap<LexerAction, Integer>();
+
+ public LexerATNFactory(LexerGrammar g) {
+ super(g);
+ // use codegen to get correct language templates for lexer commands
+ String language = g.getOptionString("language");
+ CodeGenerator gen = new CodeGenerator(g.tool, null, language);
+ codegenTemplates = gen.getTemplates();
+ }
+
+ @Override
+ public ATN createATN() {
+ // BUILD ALL START STATES (ONE PER MODE)
+ Set<String> modes = ((LexerGrammar) g).modes.keySet();
+ for (String modeName : modes) {
+ // create s0, start state; implied Tokens rule node
+ TokensStartState startState =
+ newState(TokensStartState.class, null);
+ atn.modeNameToStartState.put(modeName, startState);
+ atn.modeToStartState.add(startState);
+ atn.defineDecisionState(startState);
+ }
+
+ // INIT ACTION, RULE->TOKEN_TYPE MAP
+ atn.ruleToTokenType = new int[g.rules.size()];
+ for (Rule r : g.rules.values()) {
+ atn.ruleToTokenType[r.index] = g.getTokenType(r.name);
+ }
+
+ // CREATE ATN FOR EACH RULE
+ _createATN(g.rules.values());
+
+ atn.lexerActions = new LexerAction[indexToActionMap.size()];
+ for (Map.Entry<Integer, LexerAction> entry : indexToActionMap.entrySet()) {
+ atn.lexerActions[entry.getKey()] = entry.getValue();
+ }
+
+ // LINK MODE START STATE TO EACH TOKEN RULE
+ for (String modeName : modes) {
+ List<Rule> rules = ((LexerGrammar)g).modes.get(modeName);
+ TokensStartState startState = atn.modeNameToStartState.get(modeName);
+ for (Rule r : rules) {
+ if ( !r.isFragment() ) {
+ RuleStartState s = atn.ruleToStartState[r.index];
+ epsilon(startState, s);
+ }
+ }
+ }
+
+ ATNOptimizer.optimize(g, atn);
+ return atn;
+ }
+
+ @Override
+ public Handle action(ActionAST action) {
+ int ruleIndex = currentRule.index;
+ int actionIndex = g.lexerActions.get(action);
+ LexerCustomAction lexerAction = new LexerCustomAction(ruleIndex, actionIndex);
+ return action(action, lexerAction);
+ }
+
+ protected int getLexerActionIndex(LexerAction lexerAction) {
+ Integer lexerActionIndex = actionToIndexMap.get(lexerAction);
+ if (lexerActionIndex == null) {
+ lexerActionIndex = actionToIndexMap.size();
+ actionToIndexMap.put(lexerAction, lexerActionIndex);
+ indexToActionMap.put(lexerActionIndex, lexerAction);
+ }
+
+ return lexerActionIndex;
+ }
+
+ @Override
+ public Handle action(String action) {
+ if (action.trim().isEmpty()) {
+ ATNState left = newState(null);
+ ATNState right = newState(null);
+ epsilon(left, right);
+ return new Handle(left, right);
+ }
+
+ // define action AST for this rule as if we had found in grammar
+ ActionAST ast = new ActionAST(new CommonToken(ANTLRParser.ACTION, action));
+ currentRule.defineActionInAlt(currentOuterAlt, ast);
+ return action(ast);
+ }
+
+ protected Handle action(GrammarAST node, LexerAction lexerAction) {
+ ATNState left = newState(node);
+ ATNState right = newState(node);
+ boolean isCtxDependent = false;
+ int lexerActionIndex = getLexerActionIndex(lexerAction);
+ ActionTransition a =
+ new ActionTransition(right, currentRule.index, lexerActionIndex, isCtxDependent);
+ left.addTransition(a);
+ node.atnState = left;
+ Handle h = new Handle(left, right);
+ return h;
+ }
+
+ @Override
+ public Handle lexerAltCommands(Handle alt, Handle cmds) {
+ Handle h = new Handle(alt.left, cmds.right);
+ epsilon(alt.right, cmds.left);
+ return h;
+ }
+
+ @Override
+ public Handle lexerCallCommand(GrammarAST ID, GrammarAST arg) {
+ LexerAction lexerAction = createLexerAction(ID, arg);
+ if (lexerAction != null) {
+ return action(ID, lexerAction);
+ }
+
+ // fall back to standard action generation for the command
+ ST cmdST = codegenTemplates.getInstanceOf("Lexer" +
+ CharSupport.capitalize(ID.getText())+
+ "Command");
+ if (cmdST == null) {
+ g.tool.errMgr.grammarError(ErrorType.INVALID_LEXER_COMMAND, g.fileName, ID.token, ID.getText());
+ return epsilon(ID);
+ }
+
+ if (cmdST.impl.formalArguments == null || !cmdST.impl.formalArguments.containsKey("arg")) {
+ g.tool.errMgr.grammarError(ErrorType.UNWANTED_LEXER_COMMAND_ARGUMENT, g.fileName, ID.token, ID.getText());
+ return epsilon(ID);
+ }
+
+ cmdST.add("arg", arg.getText());
+ return action(cmdST.render());
+ }
+
+ @Override
+ public Handle lexerCommand(GrammarAST ID) {
+ LexerAction lexerAction = createLexerAction(ID, null);
+ if (lexerAction != null) {
+ return action(ID, lexerAction);
+ }
+
+ // fall back to standard action generation for the command
+ ST cmdST = codegenTemplates.getInstanceOf("Lexer" +
+ CharSupport.capitalize(ID.getText())+
+ "Command");
+ if (cmdST == null) {
+ g.tool.errMgr.grammarError(ErrorType.INVALID_LEXER_COMMAND, g.fileName, ID.token, ID.getText());
+ return epsilon(ID);
+ }
+
+ if (cmdST.impl.formalArguments != null && cmdST.impl.formalArguments.containsKey("arg")) {
+ g.tool.errMgr.grammarError(ErrorType.MISSING_LEXER_COMMAND_ARGUMENT, g.fileName, ID.token, ID.getText());
+ return epsilon(ID);
+ }
+
+ return action(cmdST.render());
+ }
+
+ @Override
+ public Handle range(GrammarAST a, GrammarAST b) {
+ ATNState left = newState(a);
+ ATNState right = newState(b);
+ int t1 = CharSupport.getCharValueFromGrammarCharLiteral(a.getText());
+ int t2 = CharSupport.getCharValueFromGrammarCharLiteral(b.getText());
+ left.addTransition(new RangeTransition(right, t1, t2));
+ a.atnState = left;
+ b.atnState = left;
+ return new Handle(left, right);
+ }
+
+ @Override
+ public Handle set(GrammarAST associatedAST, List<GrammarAST> alts, boolean invert) {
+ ATNState left = newState(associatedAST);
+ ATNState right = newState(associatedAST);
+ IntervalSet set = new IntervalSet();
+ for (GrammarAST t : alts) {
+ if ( t.getType()==ANTLRParser.RANGE ) {
+ int a = CharSupport.getCharValueFromGrammarCharLiteral(t.getChild(0).getText());
+ int b = CharSupport.getCharValueFromGrammarCharLiteral(t.getChild(1).getText());
+ set.add(a, b);
+ }
+ else if ( t.getType()==ANTLRParser.LEXER_CHAR_SET ) {
+ set.addAll(getSetFromCharSetLiteral(t));
+ }
+ else if ( t.getType()==ANTLRParser.STRING_LITERAL ) {
+ int c = CharSupport.getCharValueFromGrammarCharLiteral(t.getText());
+ if ( c != -1 ) {
+ set.add(c);
+ }
+ else {
+ g.tool.errMgr.grammarError(ErrorType.INVALID_LITERAL_IN_LEXER_SET,
+ g.fileName, t.getToken(), t.getText());
+
+ }
+ }
+ else if ( t.getType()==ANTLRParser.TOKEN_REF ) {
+ g.tool.errMgr.grammarError(ErrorType.UNSUPPORTED_REFERENCE_IN_LEXER_SET,
+ g.fileName, t.getToken(), t.getText());
+ }
+ }
+ if ( invert ) {
+ left.addTransition(new NotSetTransition(right, set));
+ }
+ else {
+ Transition transition;
+ if (set.getIntervals().size() == 1) {
+ Interval interval = set.getIntervals().get(0);
+ transition = new RangeTransition(right, interval.a, interval.b);
+ } else {
+ transition = new SetTransition(right, set);
+ }
+
+ left.addTransition(transition);
+ }
+ associatedAST.atnState = left;
+ return new Handle(left, right);
+ }
+
+ /** For a lexer, a string is a sequence of char to match. That is,
+ * "fog" is treated as 'f' 'o' 'g' not as a single transition in
+ * the DFA. Machine== o-'f'->o-'o'->o-'g'->o and has n+1 states
+ * for n characters.
+ */
+ @Override
+ public Handle stringLiteral(TerminalAST stringLiteralAST) {
+ String chars = stringLiteralAST.getText();
+ chars = CharSupport.getStringFromGrammarStringLiteral(chars);
+ int n = chars.length();
+ ATNState left = newState(stringLiteralAST);
+ ATNState prev = left;
+ ATNState right = null;
+ for (int i=0; i<n; i++) {
+ right = newState(stringLiteralAST);
+ prev.addTransition(new AtomTransition(right, chars.charAt(i)));
+ prev = right;
+ }
+ stringLiteralAST.atnState = left;
+ return new Handle(left, right);
+ }
+
+ /** [Aa\t \u1234a-z\]\-] char sets */
+ @Override
+ public Handle charSetLiteral(GrammarAST charSetAST) {
+ ATNState left = newState(charSetAST);
+ ATNState right = newState(charSetAST);
+ IntervalSet set = getSetFromCharSetLiteral(charSetAST);
+ left.addTransition(new SetTransition(right, set));
+ charSetAST.atnState = left;
+ return new Handle(left, right);
+ }
+
+ public IntervalSet getSetFromCharSetLiteral(GrammarAST charSetAST) {
+ String chars = charSetAST.getText();
+ chars = chars.substring(1, chars.length()-1);
+ String cset = '"'+ chars +'"';
+ IntervalSet set = new IntervalSet();
+
+ // unescape all valid escape char like \n, leaving escaped dashes as '\-'
+ // so we can avoid seeing them as '-' range ops.
+ chars = CharSupport.getStringFromGrammarStringLiteral(cset);
+ // now make x-y become set of char
+ int n = chars.length();
+ for (int i=0; i< n; i++) {
+ int c = chars.charAt(i);
+ if ( c=='\\' && (i+1)<n && chars.charAt(i+1)=='-' ) { // \-
+ set.add('-');
+ i++;
+ }
+ else if ( (i+2)<n && chars.charAt(i+1)=='-' ) { // range x-y
+ int x = c;
+ int y = chars.charAt(i+2);
+ if ( x<=y ) set.add(x,y);
+ i+=2;
+ }
+ else {
+ set.add(c);
+ }
+ }
+ return set;
+ }
+
+ @Override
+ public Handle tokenRef(TerminalAST node) {
+ // Ref to EOF in lexer yields char transition on -1
+ if ( node.getText().equals("EOF") ) {
+ ATNState left = newState(node);
+ ATNState right = newState(node);
+ left.addTransition(new AtomTransition(right, IntStream.EOF));
+ return new Handle(left, right);
+ }
+ return _ruleRef(node);
+ }
+
+
+ protected LexerAction createLexerAction(GrammarAST ID, GrammarAST arg) {
+ String command = ID.getText();
+ if ("skip".equals(command) && arg == null) {
+ return LexerSkipAction.INSTANCE;
+ }
+ else if ("more".equals(command) && arg == null) {
+ return LexerMoreAction.INSTANCE;
+ }
+ else if ("popMode".equals(command) && arg == null) {
+ return LexerPopModeAction.INSTANCE;
+ }
+ else if ("mode".equals(command) && arg != null) {
+ String modeName = arg.getText();
+ Integer mode = getConstantValue(modeName, arg.getToken());
+ if (mode == null) {
+ return null;
+ }
+
+ return new LexerModeAction(mode);
+ }
+ else if ("pushMode".equals(command) && arg != null) {
+ String modeName = arg.getText();
+ Integer mode = getConstantValue(modeName, arg.getToken());
+ if (mode == null) {
+ return null;
+ }
+
+ return new LexerPushModeAction(mode);
+ }
+ else if ("type".equals(command) && arg != null) {
+ String typeName = arg.getText();
+ Integer type = getConstantValue(typeName, arg.getToken());
+ if (type == null) {
+ return null;
+ }
+
+ return new LexerTypeAction(type);
+ }
+ else if ("channel".equals(command) && arg != null) {
+ String channelName = arg.getText();
+ Integer channel = getConstantValue(channelName, arg.getToken());
+ if (channel == null) {
+ return null;
+ }
+
+ return new LexerChannelAction(channel);
+ }
+ else {
+ return null;
+ }
+ }
+
+
+ protected Integer getConstantValue(String name, Token token) {
+ if (name == null) {
+ return null;
+ }
+
+ Integer commonConstant = COMMON_CONSTANTS.get(name);
+ if (commonConstant != null) {
+ return commonConstant;
+ }
+
+ int tokenType = g.getTokenType(name);
+ if (tokenType != org.antlr.v4.runtime.Token.INVALID_TYPE) {
+ return tokenType;
+ }
+
+ int channelValue = g.getChannelValue(name);
+ if (channelValue >= org.antlr.v4.runtime.Token.MIN_USER_CHANNEL_VALUE) {
+ return channelValue;
+ }
+
+ List<String> modeNames = new ArrayList<String>(((LexerGrammar)g).modes.keySet());
+ int mode = modeNames.indexOf(name);
+ if (mode >= 0) {
+ return mode;
+ }
+
+ try {
+ return Integer.parseInt(name);
+ } catch (NumberFormatException ex) {
+ g.tool.errMgr.grammarError(ErrorType.UNKNOWN_LEXER_CONSTANT, g.fileName, token, currentRule.name, token != null ? token.getText() : null);
+ return null;
+ }
+ }
+}
diff --git a/tool/src/org/antlr/v4/automata/ParserATNFactory.java b/tool/src/org/antlr/v4/automata/ParserATNFactory.java
new file mode 100644
index 0000000..3664111
--- /dev/null
+++ b/tool/src/org/antlr/v4/automata/ParserATNFactory.java
@@ -0,0 +1,797 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.automata;
+
+
+import org.antlr.runtime.RecognitionException;
+import org.antlr.runtime.Token;
+import org.antlr.runtime.tree.CommonTreeNodeStream;
+import org.antlr.runtime.tree.Tree;
+import org.antlr.v4.analysis.LeftRecursiveRuleTransformer;
+import org.antlr.v4.misc.CharSupport;
+import org.antlr.v4.parse.ANTLRParser;
+import org.antlr.v4.parse.ATNBuilder;
+import org.antlr.v4.parse.GrammarASTAdaptor;
+import org.antlr.v4.runtime.atn.ATN;
+import org.antlr.v4.runtime.atn.ATNState;
+import org.antlr.v4.runtime.atn.ATNType;
+import org.antlr.v4.runtime.atn.AbstractPredicateTransition;
+import org.antlr.v4.runtime.atn.ActionTransition;
+import org.antlr.v4.runtime.atn.AtomTransition;
+import org.antlr.v4.runtime.atn.BasicBlockStartState;
+import org.antlr.v4.runtime.atn.BasicState;
+import org.antlr.v4.runtime.atn.BlockEndState;
+import org.antlr.v4.runtime.atn.BlockStartState;
+import org.antlr.v4.runtime.atn.EpsilonTransition;
+import org.antlr.v4.runtime.atn.LL1Analyzer;
+import org.antlr.v4.runtime.atn.LoopEndState;
+import org.antlr.v4.runtime.atn.NotSetTransition;
+import org.antlr.v4.runtime.atn.PlusBlockStartState;
+import org.antlr.v4.runtime.atn.PlusLoopbackState;
+import org.antlr.v4.runtime.atn.PrecedencePredicateTransition;
+import org.antlr.v4.runtime.atn.PredicateTransition;
+import org.antlr.v4.runtime.atn.RuleStartState;
+import org.antlr.v4.runtime.atn.RuleStopState;
+import org.antlr.v4.runtime.atn.RuleTransition;
+import org.antlr.v4.runtime.atn.SetTransition;
+import org.antlr.v4.runtime.atn.StarBlockStartState;
+import org.antlr.v4.runtime.atn.StarLoopEntryState;
+import org.antlr.v4.runtime.atn.StarLoopbackState;
+import org.antlr.v4.runtime.atn.Transition;
+import org.antlr.v4.runtime.atn.WildcardTransition;
+import org.antlr.v4.runtime.misc.IntervalSet;
+import org.antlr.v4.runtime.misc.Triple;
+import org.antlr.v4.semantics.UseDefAnalyzer;
+import org.antlr.v4.tool.ErrorManager;
+import org.antlr.v4.tool.ErrorType;
+import org.antlr.v4.tool.Grammar;
+import org.antlr.v4.tool.LeftRecursiveRule;
+import org.antlr.v4.tool.LexerGrammar;
+import org.antlr.v4.tool.Rule;
+import org.antlr.v4.tool.ast.ActionAST;
+import org.antlr.v4.tool.ast.AltAST;
+import org.antlr.v4.tool.ast.BlockAST;
+import org.antlr.v4.tool.ast.GrammarAST;
+import org.antlr.v4.tool.ast.GrammarASTWithOptions;
+import org.antlr.v4.tool.ast.PredAST;
+import org.antlr.v4.tool.ast.QuantifierAST;
+import org.antlr.v4.tool.ast.TerminalAST;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/** ATN construction routines triggered by ATNBuilder.g.
+ *
+ * No side-effects. It builds an {@link ATN} object and returns it.
+ */
+public class ParserATNFactory implements ATNFactory {
+
+ public final Grammar g;
+
+
+ public final ATN atn;
+
+ public Rule currentRule;
+
+ public int currentOuterAlt;
+
+
+ protected final List<Triple<Rule, ATNState, ATNState>> preventEpsilonClosureBlocks =
+ new ArrayList<Triple<Rule, ATNState, ATNState>>();
+
+
+ protected final List<Triple<Rule, ATNState, ATNState>> preventEpsilonOptionalBlocks =
+ new ArrayList<Triple<Rule, ATNState, ATNState>>();
+
+ public ParserATNFactory(Grammar g) {
+ if (g == null) {
+ throw new NullPointerException("g");
+ }
+
+ this.g = g;
+
+ ATNType atnType = g instanceof LexerGrammar ? ATNType.LEXER : ATNType.PARSER;
+ int maxTokenType = g.getMaxTokenType();
+ this.atn = new ATN(atnType, maxTokenType);
+ }
+
+
+ @Override
+ public ATN createATN() {
+ _createATN(g.rules.values());
+ assert atn.maxTokenType == g.getMaxTokenType();
+ addRuleFollowLinks();
+ addEOFTransitionToStartRules();
+ ATNOptimizer.optimize(g, atn);
+
+ for (Triple<Rule, ATNState, ATNState> pair : preventEpsilonClosureBlocks) {
+ LL1Analyzer analyzer = new LL1Analyzer(atn);
+ if (analyzer.LOOK(pair.b, pair.c, null).contains(org.antlr.v4.runtime.Token.EPSILON)) {
+ ErrorType errorType = pair.a instanceof LeftRecursiveRule ? ErrorType.EPSILON_LR_FOLLOW : ErrorType.EPSILON_CLOSURE;
+ g.tool.errMgr.grammarError(errorType, g.fileName, ((GrammarAST)pair.a.ast.getChild(0)).getToken(), pair.a.name);
+ }
+ }
+
+ optionalCheck:
+ for (Triple<Rule, ATNState, ATNState> pair : preventEpsilonOptionalBlocks) {
+ int bypassCount = 0;
+ for (int i = 0; i < pair.b.getNumberOfTransitions(); i++) {
+ ATNState startState = pair.b.transition(i).target;
+ if (startState == pair.c) {
+ bypassCount++;
+ continue;
+ }
+
+ LL1Analyzer analyzer = new LL1Analyzer(atn);
+ if (analyzer.LOOK(startState, pair.c, null).contains(org.antlr.v4.runtime.Token.EPSILON)) {
+ g.tool.errMgr.grammarError(ErrorType.EPSILON_OPTIONAL, g.fileName, ((GrammarAST)pair.a.ast.getChild(0)).getToken(), pair.a.name);
+ continue optionalCheck;
+ }
+ }
+
+ if (bypassCount != 1) {
+ throw new UnsupportedOperationException("Expected optional block with exactly 1 bypass alternative.");
+ }
+ }
+
+ return atn;
+ }
+
+ protected void _createATN(Collection<Rule> rules) {
+ createRuleStartAndStopATNStates();
+
+ GrammarASTAdaptor adaptor = new GrammarASTAdaptor();
+ for (Rule r : rules) {
+ // find rule's block
+ GrammarAST blk = (GrammarAST)r.ast.getFirstChildWithType(ANTLRParser.BLOCK);
+ CommonTreeNodeStream nodes = new CommonTreeNodeStream(adaptor,blk);
+ ATNBuilder b = new ATNBuilder(nodes,this);
+ try {
+ setCurrentRuleName(r.name);
+ Handle h = b.ruleBlock(null);
+ rule(r.ast, r.name, h);
+ }
+ catch (RecognitionException re) {
+ ErrorManager.fatalInternalError("bad grammar AST structure", re);
+ }
+ }
+ }
+
+ @Override
+ public void setCurrentRuleName(String name) {
+ this.currentRule = g.getRule(name);
+ }
+
+ @Override
+ public void setCurrentOuterAlt(int alt) {
+ currentOuterAlt = alt;
+ }
+
+ /* start->ruleblock->end */
+
+ @Override
+ public Handle rule(GrammarAST ruleAST, String name, Handle blk) {
+ Rule r = g.getRule(name);
+ RuleStartState start = atn.ruleToStartState[r.index];
+ epsilon(start, blk.left);
+ RuleStopState stop = atn.ruleToStopState[r.index];
+ epsilon(blk.right, stop);
+ Handle h = new Handle(start, stop);
+// ATNPrinter ser = new ATNPrinter(g, h.left);
+// System.out.println(ruleAST.toStringTree()+":\n"+ser.asString());
+ ruleAST.atnState = start;
+ return h;
+ }
+
+ /** From label {@code A} build graph {@code o-A->o}. */
+
+ @Override
+ public Handle tokenRef(TerminalAST node) {
+ ATNState left = newState(node);
+ ATNState right = newState(node);
+ int ttype = g.getTokenType(node.getText());
+ left.addTransition(new AtomTransition(right, ttype));
+ node.atnState = left;
+ return new Handle(left, right);
+ }
+
+ /** From set build single edge graph {@code o->o-set->o}. To conform to
+ * what an alt block looks like, must have extra state on left.
+ * This also handles {@code ~A}, converted to {@code ~{A}} set.
+ */
+
+ @Override
+ public Handle set(GrammarAST associatedAST, List<GrammarAST> terminals, boolean invert) {
+ ATNState left = newState(associatedAST);
+ ATNState right = newState(associatedAST);
+ IntervalSet set = new IntervalSet();
+ for (GrammarAST t : terminals) {
+ int ttype = g.getTokenType(t.getText());
+ set.add(ttype);
+ }
+ if ( invert ) {
+ left.addTransition(new NotSetTransition(right, set));
+ }
+ else {
+ left.addTransition(new SetTransition(right, set));
+ }
+ associatedAST.atnState = left;
+ return new Handle(left, right);
+ }
+
+ /** Not valid for non-lexers. */
+
+ @Override
+ public Handle range(GrammarAST a, GrammarAST b) {
+ throw new UnsupportedOperationException("This construct is not valid in parsers.");
+ }
+
+ protected int getTokenType(GrammarAST atom) {
+ int ttype;
+ if ( g.isLexer() ) {
+ ttype = CharSupport.getCharValueFromGrammarCharLiteral(atom.getText());
+ }
+ else {
+ ttype = g.getTokenType(atom.getText());
+ }
+ return ttype;
+ }
+
+ /** For a non-lexer, just build a simple token reference atom. */
+
+ @Override
+ public Handle stringLiteral(TerminalAST stringLiteralAST) {
+ return tokenRef(stringLiteralAST);
+ }
+
+ /** {@code [Aa]} char sets not allowed in parser */
+
+ @Override
+ public Handle charSetLiteral(GrammarAST charSetAST) {
+ return null;
+ }
+
+ /**
+ * For reference to rule {@code r}, build
+ *
+ * <pre>
+ * o->(r) o
+ * </pre>
+ *
+ * where {@code (r)} is the start of rule {@code r} and the trailing
+ * {@code o} is not linked to from rule ref state directly (uses
+ * {@link RuleTransition#followState}).
+ */
+
+ @Override
+ public Handle ruleRef(GrammarAST node) {
+ Handle h = _ruleRef(node);
+ return h;
+ }
+
+
+ public Handle _ruleRef(GrammarAST node) {
+ Rule r = g.getRule(node.getText());
+ if ( r==null ) {
+ g.tool.errMgr.grammarError(ErrorType.INTERNAL_ERROR, g.fileName, node.getToken(), "Rule "+node.getText()+" undefined");
+ return null;
+ }
+ RuleStartState start = atn.ruleToStartState[r.index];
+ ATNState left = newState(node);
+ ATNState right = newState(node);
+ int precedence = 0;
+ if (((GrammarASTWithOptions)node).getOptionString(LeftRecursiveRuleTransformer.PRECEDENCE_OPTION_NAME) != null) {
+ precedence = Integer.parseInt(((GrammarASTWithOptions)node).getOptionString(LeftRecursiveRuleTransformer.PRECEDENCE_OPTION_NAME));
+ }
+ RuleTransition call = new RuleTransition(start, r.index, precedence, right);
+ left.addTransition(call);
+
+ node.atnState = left;
+ return new Handle(left, right);
+ }
+
+ public void addFollowLink(int ruleIndex, ATNState right) {
+ // add follow edge from end of invoked rule
+ RuleStopState stop = atn.ruleToStopState[ruleIndex];
+// System.out.println("add follow link from "+ruleIndex+" to "+right);
+ epsilon(stop, right);
+ }
+
+ /** From an empty alternative build {@code o-e->o}. */
+
+ @Override
+ public Handle epsilon(GrammarAST node) {
+ ATNState left = newState(node);
+ ATNState right = newState(node);
+ epsilon(left, right);
+ node.atnState = left;
+ return new Handle(left, right);
+ }
+
+ /** Build what amounts to an epsilon transition with a semantic
+ * predicate action. The {@code pred} is a pointer into the AST of
+ * the {@link ANTLRParser#SEMPRED} token.
+ */
+
+ @Override
+ public Handle sempred(PredAST pred) {
+ //System.out.println("sempred: "+ pred);
+ ATNState left = newState(pred);
+ ATNState right = newState(pred);
+
+ AbstractPredicateTransition p;
+ if (pred.getOptionString(LeftRecursiveRuleTransformer.PRECEDENCE_OPTION_NAME) != null) {
+ int precedence = Integer.parseInt(pred.getOptionString(LeftRecursiveRuleTransformer.PRECEDENCE_OPTION_NAME));
+ p = new PrecedencePredicateTransition(right, precedence);
+ }
+ else {
+ boolean isCtxDependent = UseDefAnalyzer.actionIsContextDependent(pred);
+ p = new PredicateTransition(right, currentRule.index, g.sempreds.get(pred), isCtxDependent);
+ }
+
+ left.addTransition(p);
+ pred.atnState = left;
+ return new Handle(left, right);
+ }
+
+ /** Build what amounts to an epsilon transition with an action.
+ * The action goes into ATN though it is ignored during prediction
+ * if {@link ActionTransition#actionIndex actionIndex}{@code <0}.
+ */
+
+ @Override
+ public Handle action(ActionAST action) {
+ //System.out.println("action: "+action);
+ ATNState left = newState(action);
+ ATNState right = newState(action);
+ ActionTransition a = new ActionTransition(right, currentRule.index);
+ left.addTransition(a);
+ action.atnState = left;
+ return new Handle(left, right);
+ }
+
+
+ @Override
+ public Handle action(String action) {
+ throw new UnsupportedOperationException("This element is not valid in parsers.");
+ }
+
+ /**
+ * From {@code A|B|..|Z} alternative block build
+ *
+ * <pre>
+ * o->o-A->o->o (last ATNState is BlockEndState pointed to by all alts)
+ * | ^
+ * |->o-B->o--|
+ * | |
+ * ... |
+ * | |
+ * |->o-Z->o--|
+ * </pre>
+ *
+ * So start node points at every alternative with epsilon transition and
+ * every alt right side points at a block end ATNState.
+ * <p/>
+ * Special case: only one alternative: don't make a block with alt
+ * begin/end.
+ * <p/>
+ * Special case: if just a list of tokens/chars/sets, then collapse to a
+ * single edged o-set->o graph.
+ * <p/>
+ * TODO: Set alt number (1..n) in the states?
+ */
+
+ @Override
+ public Handle block(BlockAST blkAST, GrammarAST ebnfRoot, List<Handle> alts) {
+ if ( ebnfRoot==null ) {
+ if ( alts.size()==1 ) {
+ Handle h = alts.get(0);
+ blkAST.atnState = h.left;
+ return h;
+ }
+ BlockStartState start = newState(BasicBlockStartState.class, blkAST);
+ if ( alts.size()>1 ) atn.defineDecisionState(start);
+ return makeBlock(start, blkAST, alts);
+ }
+ switch ( ebnfRoot.getType() ) {
+ case ANTLRParser.OPTIONAL :
+ BlockStartState start = newState(BasicBlockStartState.class, blkAST);
+ atn.defineDecisionState(start);
+ Handle h = makeBlock(start, blkAST, alts);
+ return optional(ebnfRoot, h);
+ case ANTLRParser.CLOSURE :
+ BlockStartState star = newState(StarBlockStartState.class, ebnfRoot);
+ if ( alts.size()>1 ) atn.defineDecisionState(star);
+ h = makeBlock(star, blkAST, alts);
+ return star(ebnfRoot, h);
+ case ANTLRParser.POSITIVE_CLOSURE :
+ PlusBlockStartState plus = newState(PlusBlockStartState.class, ebnfRoot);
+ if ( alts.size()>1 ) atn.defineDecisionState(plus);
+ h = makeBlock(plus, blkAST, alts);
+ return plus(ebnfRoot, h);
+ }
+ return null;
+ }
+
+
+ protected Handle makeBlock(BlockStartState start, BlockAST blkAST, List<Handle> alts) {
+ BlockEndState end = newState(BlockEndState.class, blkAST);
+ start.endState = end;
+ for (Handle alt : alts) {
+ // hook alts up to decision block
+ epsilon(start, alt.left);
+ epsilon(alt.right, end);
+ // no back link in ATN so must walk entire alt to see if we can
+ // strip out the epsilon to 'end' state
+ TailEpsilonRemover opt = new TailEpsilonRemover(atn);
+ opt.visit(alt.left);
+ }
+ Handle h = new Handle(start, end);
+// FASerializer ser = new FASerializer(g, h.left);
+// System.out.println(blkAST.toStringTree()+":\n"+ser);
+ blkAST.atnState = start;
+
+ return h;
+ }
+
+
+ @Override
+ public Handle alt(List<Handle> els) {
+ return elemList(els);
+ }
+
+
+ public Handle elemList(List<Handle> els) {
+ int n = els.size();
+ for (int i = 0; i < n - 1; i++) { // hook up elements (visit all but last)
+ Handle el = els.get(i);
+ // if el is of form o-x->o for x in {rule, action, pred, token, ...}
+ // and not last in alt
+ Transition tr = null;
+ if ( el.left.getNumberOfTransitions()==1 ) tr = el.left.transition(0);
+ boolean isRuleTrans = tr instanceof RuleTransition;
+ if ( el.left.getStateType() == ATNState.BASIC &&
+ el.right.getStateType()== ATNState.BASIC &&
+ tr!=null && (isRuleTrans && ((RuleTransition)tr).followState == el.right || tr.target == el.right) )
+ {
+ // we can avoid epsilon edge to next el
+ if ( isRuleTrans ) ((RuleTransition)tr).followState = els.get(i+1).left;
+ else tr.target = els.get(i+1).left;
+ atn.removeState(el.right); // we skipped over this state
+ }
+ else { // need epsilon if previous block's right end node is complicated
+ epsilon(el.right, els.get(i+1).left);
+ }
+ }
+ Handle first = els.get(0);
+ Handle last = els.get(n -1);
+ if ( first==null || last==null ) {
+ g.tool.errMgr.toolError(ErrorType.INTERNAL_ERROR, "element list has first|last == null");
+ }
+ return new Handle(first.left, last.right);
+ }
+
+ /**
+ * From {@code (A)?} build either:
+ *
+ * <pre>
+ * o--A->o
+ * | ^
+ * o---->|
+ * </pre>
+ *
+ * or, if {@code A} is a block, just add an empty alt to the end of the
+ * block
+ */
+
+ @Override
+ public Handle optional(GrammarAST optAST, Handle blk) {
+ BlockStartState blkStart = (BlockStartState)blk.left;
+ ATNState blkEnd = blk.right;
+ preventEpsilonOptionalBlocks.add(new Triple<Rule, ATNState, ATNState>(currentRule, blkStart, blkEnd));
+
+ boolean greedy = ((QuantifierAST)optAST).isGreedy();
+ blkStart.nonGreedy = !greedy;
+ epsilon(blkStart, blk.right, !greedy);
+
+ optAST.atnState = blk.left;
+ return blk;
+ }
+
+ /**
+ * From {@code (blk)+} build
+ *
+ * <pre>
+ * |---------|
+ * v |
+ * [o-blk-o]->o->o
+ * </pre>
+ *
+ * We add a decision for loop back node to the existing one at {@code blk}
+ * start.
+ */
+
+ @Override
+ public Handle plus(GrammarAST plusAST, Handle blk) {
+ PlusBlockStartState blkStart = (PlusBlockStartState)blk.left;
+ BlockEndState blkEnd = (BlockEndState)blk.right;
+ preventEpsilonClosureBlocks.add(new Triple<Rule, ATNState, ATNState>(currentRule, blkStart, blkEnd));
+
+ PlusLoopbackState loop = newState(PlusLoopbackState.class, plusAST);
+ loop.nonGreedy = !((QuantifierAST)plusAST).isGreedy();
+ atn.defineDecisionState(loop);
+ LoopEndState end = newState(LoopEndState.class, plusAST);
+ blkStart.loopBackState = loop;
+ end.loopBackState = loop;
+
+ plusAST.atnState = loop;
+ epsilon(blkEnd, loop); // blk can see loop back
+
+ BlockAST blkAST = (BlockAST)plusAST.getChild(0);
+ if ( ((QuantifierAST)plusAST).isGreedy() ) {
+ if (expectNonGreedy(blkAST)) {
+ g.tool.errMgr.grammarError(ErrorType.EXPECTED_NON_GREEDY_WILDCARD_BLOCK, g.fileName, plusAST.getToken(), plusAST.getToken().getText());
+ }
+
+ epsilon(loop, blkStart); // loop back to start
+ epsilon(loop, end); // or exit
+ }
+ else {
+ // if not greedy, priority to exit branch; make it first
+ epsilon(loop, end); // exit
+ epsilon(loop, blkStart); // loop back to start
+ }
+
+ return new Handle(blkStart, end);
+ }
+
+ /**
+ * From {@code (blk)*} build {@code ( blk+ )?} with *two* decisions, one for
+ * entry and one for choosing alts of {@code blk}.
+ *
+ * <pre>
+ * |-------------|
+ * v |
+ * o--[o-blk-o]->o o
+ * | ^
+ * -----------------|
+ * </pre>
+ *
+ * Note that the optional bypass must jump outside the loop as
+ * {@code (A|B)*} is not the same thing as {@code (A|B|)+}.
+ */
+
+ @Override
+ public Handle star(GrammarAST starAST, Handle elem) {
+ StarBlockStartState blkStart = (StarBlockStartState)elem.left;
+ BlockEndState blkEnd = (BlockEndState)elem.right;
+ preventEpsilonClosureBlocks.add(new Triple<Rule, ATNState, ATNState>(currentRule, blkStart, blkEnd));
+
+ StarLoopEntryState entry = newState(StarLoopEntryState.class, starAST);
+ entry.nonGreedy = !((QuantifierAST)starAST).isGreedy();
+ atn.defineDecisionState(entry);
+ LoopEndState end = newState(LoopEndState.class, starAST);
+ StarLoopbackState loop = newState(StarLoopbackState.class, starAST);
+ entry.loopBackState = loop;
+ end.loopBackState = loop;
+
+ BlockAST blkAST = (BlockAST)starAST.getChild(0);
+ if ( ((QuantifierAST)starAST).isGreedy() ) {
+ if (expectNonGreedy(blkAST)) {
+ g.tool.errMgr.grammarError(ErrorType.EXPECTED_NON_GREEDY_WILDCARD_BLOCK, g.fileName, starAST.getToken(), starAST.getToken().getText());
+ }
+
+ epsilon(entry, blkStart); // loop enter edge (alt 1)
+ epsilon(entry, end); // bypass loop edge (alt 2)
+ }
+ else {
+ // if not greedy, priority to exit branch; make it first
+ epsilon(entry, end); // bypass loop edge (alt 1)
+ epsilon(entry, blkStart); // loop enter edge (alt 2)
+ }
+ epsilon(blkEnd, loop); // block end hits loop back
+ epsilon(loop, entry); // loop back to entry/exit decision
+
+ starAST.atnState = entry; // decision is to enter/exit; blk is its own decision
+ return new Handle(entry, end);
+ }
+
+ /** Build an atom with all possible values in its label. */
+
+ @Override
+ public Handle wildcard(GrammarAST node) {
+ ATNState left = newState(node);
+ ATNState right = newState(node);
+ left.addTransition(new WildcardTransition(right));
+ node.atnState = left;
+ return new Handle(left, right);
+ }
+
+ protected void epsilon(ATNState a, ATNState b) {
+ epsilon(a, b, false);
+ }
+
+ protected void epsilon(ATNState a, ATNState b, boolean prepend) {
+ if ( a!=null ) {
+ int index = prepend ? 0 : a.getNumberOfTransitions();
+ a.addTransition(index, new EpsilonTransition(b));
+ }
+ }
+
+ /** Define all the rule begin/end ATNStates to solve forward reference
+ * issues.
+ */
+ void createRuleStartAndStopATNStates() {
+ atn.ruleToStartState = new RuleStartState[g.rules.size()];
+ atn.ruleToStopState = new RuleStopState[g.rules.size()];
+ for (Rule r : g.rules.values()) {
+ RuleStartState start = newState(RuleStartState.class, r.ast);
+ RuleStopState stop = newState(RuleStopState.class, r.ast);
+ start.stopState = stop;
+ start.isLeftRecursiveRule = r instanceof LeftRecursiveRule;
+ start.setRuleIndex(r.index);
+ stop.setRuleIndex(r.index);
+ atn.ruleToStartState[r.index] = start;
+ atn.ruleToStopState[r.index] = stop;
+ }
+ }
+
+ public void addRuleFollowLinks() {
+ for (ATNState p : atn.states) {
+ if ( p!=null &&
+ p.getStateType() == ATNState.BASIC && p.getNumberOfTransitions()==1 &&
+ p.transition(0) instanceof RuleTransition )
+ {
+ RuleTransition rt = (RuleTransition) p.transition(0);
+ addFollowLink(rt.ruleIndex, rt.followState);
+ }
+ }
+ }
+
+ /** Add an EOF transition to any rule end ATNState that points to nothing
+ * (i.e., for all those rules not invoked by another rule). These
+ * are start symbols then.
+ *
+ * Return the number of grammar entry points; i.e., how many rules are
+ * not invoked by another rule (they can only be invoked from outside).
+ * These are the start rules.
+ */
+ public int addEOFTransitionToStartRules() {
+ int n = 0;
+ ATNState eofTarget = newState(null); // one unique EOF target for all rules
+ for (Rule r : g.rules.values()) {
+ ATNState stop = atn.ruleToStopState[r.index];
+ if ( stop.getNumberOfTransitions()>0 ) continue;
+ n++;
+ Transition t = new AtomTransition(eofTarget, Token.EOF);
+ stop.addTransition(t);
+ }
+ return n;
+ }
+
+
+ @Override
+ public Handle label(Handle t) {
+ return t;
+ }
+
+
+ @Override
+ public Handle listLabel(Handle t) {
+ return t;
+ }
+
+
+ public <T extends ATNState> T newState(Class<T> nodeType, GrammarAST node) {
+ Exception cause;
+ try {
+ Constructor<T> ctor = nodeType.getConstructor();
+ T s = ctor.newInstance();
+ if ( currentRule==null ) s.setRuleIndex(-1);
+ else s.setRuleIndex(currentRule.index);
+ atn.addState(s);
+ return s;
+ } catch (InstantiationException ex) {
+ cause = ex;
+ } catch (IllegalAccessException ex) {
+ cause = ex;
+ } catch (IllegalArgumentException ex) {
+ cause = ex;
+ } catch (InvocationTargetException ex) {
+ cause = ex;
+ } catch (NoSuchMethodException ex) {
+ cause = ex;
+ } catch (SecurityException ex) {
+ cause = ex;
+ }
+
+ String message = String.format("Could not create %s of type %s.", ATNState.class.getName(), nodeType.getName());
+ throw new UnsupportedOperationException(message, cause);
+ }
+
+
+ public ATNState newState(GrammarAST node) {
+ ATNState n = new BasicState();
+ n.setRuleIndex(currentRule.index);
+ atn.addState(n);
+ return n;
+ }
+
+
+ @Override
+ public ATNState newState() { return newState(null); }
+
+ public boolean expectNonGreedy(BlockAST blkAST) {
+ if ( blockHasWildcardAlt(blkAST) ) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * {@code (BLOCK (ALT .))} or {@code (BLOCK (ALT 'a') (ALT .))}.
+ */
+ public static boolean blockHasWildcardAlt(GrammarAST block) {
+ for (Object alt : block.getChildren()) {
+ if ( !(alt instanceof AltAST) ) continue;
+ AltAST altAST = (AltAST)alt;
+ if ( altAST.getChildCount()==1 || (altAST.getChildCount() == 2 && altAST.getChild(0).getType() == ANTLRParser.ELEMENT_OPTIONS) ) {
+ Tree e = altAST.getChild(altAST.getChildCount() - 1);
+ if ( e.getType()==ANTLRParser.WILDCARD ) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+
+ @Override
+ public Handle lexerAltCommands(Handle alt, Handle cmds) {
+ throw new UnsupportedOperationException("This element is not allowed in parsers.");
+ }
+
+
+ @Override
+ public Handle lexerCallCommand(GrammarAST ID, GrammarAST arg) {
+ throw new UnsupportedOperationException("This element is not allowed in parsers.");
+ }
+
+
+ @Override
+ public Handle lexerCommand(GrammarAST ID) {
+ throw new UnsupportedOperationException("This element is not allowed in parsers.");
+ }
+}
diff --git a/tool/src/org/antlr/v4/automata/TailEpsilonRemover.java b/tool/src/org/antlr/v4/automata/TailEpsilonRemover.java
new file mode 100644
index 0000000..35d1594
--- /dev/null
+++ b/tool/src/org/antlr/v4/automata/TailEpsilonRemover.java
@@ -0,0 +1,81 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.automata;
+
+import org.antlr.v4.runtime.atn.ATN;
+import org.antlr.v4.runtime.atn.ATNState;
+import org.antlr.v4.runtime.atn.BlockEndState;
+import org.antlr.v4.runtime.atn.EpsilonTransition;
+import org.antlr.v4.runtime.atn.PlusLoopbackState;
+import org.antlr.v4.runtime.atn.RuleTransition;
+import org.antlr.v4.runtime.atn.StarLoopbackState;
+import org.antlr.v4.runtime.atn.Transition;
+
+/**
+ *
+ * @author Terence Parr
+ */
+public class TailEpsilonRemover extends ATNVisitor {
+
+ private final ATN _atn;
+
+ public TailEpsilonRemover(ATN atn) {
+ this._atn = atn;
+ }
+
+ @Override
+ public void visitState(ATNState p) {
+ if (p.getStateType() == ATNState.BASIC && p.getNumberOfTransitions() == 1) {
+ ATNState q = p.transition(0).target;
+ if (p.transition(0) instanceof RuleTransition) {
+ q = ((RuleTransition) p.transition(0)).followState;
+ }
+ if (q.getStateType() == ATNState.BASIC) {
+ // we have p-x->q for x in {rule, action, pred, token, ...}
+ // if edge out of q is single epsilon to block end
+ // we can strip epsilon p-x->q-eps->r
+ Transition trans = q.transition(0);
+ if (q.getNumberOfTransitions() == 1 && trans instanceof EpsilonTransition) {
+ ATNState r = trans.target;
+ if (r instanceof BlockEndState || r instanceof PlusLoopbackState || r instanceof StarLoopbackState) {
+ // skip over q
+ if (p.transition(0) instanceof RuleTransition) {
+ ((RuleTransition) p.transition(0)).followState = r;
+ } else {
+ p.transition(0).target = r;
+ }
+ _atn.removeState(q);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/ActionTranslator.java b/tool/src/org/antlr/v4/codegen/ActionTranslator.java
new file mode 100644
index 0000000..2a12e8e
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/ActionTranslator.java
@@ -0,0 +1,322 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen;
+
+import org.antlr.runtime.ANTLRStringStream;
+import org.antlr.runtime.Token;
+import org.antlr.v4.codegen.model.RuleFunction;
+import org.antlr.v4.codegen.model.chunk.ActionChunk;
+import org.antlr.v4.codegen.model.chunk.ActionText;
+import org.antlr.v4.codegen.model.chunk.ArgRef;
+import org.antlr.v4.codegen.model.chunk.LabelRef;
+import org.antlr.v4.codegen.model.chunk.ListLabelRef;
+import org.antlr.v4.codegen.model.chunk.LocalRef;
+import org.antlr.v4.codegen.model.chunk.NonLocalAttrRef;
+import org.antlr.v4.codegen.model.chunk.QRetValueRef;
+import org.antlr.v4.codegen.model.chunk.RetValueRef;
+import org.antlr.v4.codegen.model.chunk.RulePropertyRef;
+import org.antlr.v4.codegen.model.chunk.RulePropertyRef_ctx;
+import org.antlr.v4.codegen.model.chunk.RulePropertyRef_parser;
+import org.antlr.v4.codegen.model.chunk.RulePropertyRef_start;
+import org.antlr.v4.codegen.model.chunk.RulePropertyRef_stop;
+import org.antlr.v4.codegen.model.chunk.RulePropertyRef_text;
+import org.antlr.v4.codegen.model.chunk.SetAttr;
+import org.antlr.v4.codegen.model.chunk.SetNonLocalAttr;
+import org.antlr.v4.codegen.model.chunk.ThisRulePropertyRef_ctx;
+import org.antlr.v4.codegen.model.chunk.ThisRulePropertyRef_parser;
+import org.antlr.v4.codegen.model.chunk.ThisRulePropertyRef_start;
+import org.antlr.v4.codegen.model.chunk.ThisRulePropertyRef_stop;
+import org.antlr.v4.codegen.model.chunk.ThisRulePropertyRef_text;
+import org.antlr.v4.codegen.model.chunk.TokenPropertyRef;
+import org.antlr.v4.codegen.model.chunk.TokenPropertyRef_channel;
+import org.antlr.v4.codegen.model.chunk.TokenPropertyRef_index;
+import org.antlr.v4.codegen.model.chunk.TokenPropertyRef_int;
+import org.antlr.v4.codegen.model.chunk.TokenPropertyRef_line;
+import org.antlr.v4.codegen.model.chunk.TokenPropertyRef_pos;
+import org.antlr.v4.codegen.model.chunk.TokenPropertyRef_text;
+import org.antlr.v4.codegen.model.chunk.TokenPropertyRef_type;
+import org.antlr.v4.codegen.model.chunk.TokenRef;
+import org.antlr.v4.codegen.model.decl.StructDecl;
+import org.antlr.v4.parse.ActionSplitter;
+import org.antlr.v4.parse.ActionSplitterListener;
+import org.antlr.v4.tool.Attribute;
+import org.antlr.v4.tool.ErrorType;
+import org.antlr.v4.tool.Grammar;
+import org.antlr.v4.tool.Rule;
+import org.antlr.v4.tool.ast.ActionAST;
+
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/** */
+public class ActionTranslator implements ActionSplitterListener {
+ public static final Map<String, Class<? extends RulePropertyRef>> thisRulePropToModelMap =
+ new HashMap<String, Class<? extends RulePropertyRef>>();
+ static {
+ thisRulePropToModelMap.put("start", ThisRulePropertyRef_start.class);
+ thisRulePropToModelMap.put("stop", ThisRulePropertyRef_stop.class);
+ thisRulePropToModelMap.put("text", ThisRulePropertyRef_text.class);
+ thisRulePropToModelMap.put("ctx", ThisRulePropertyRef_ctx.class);
+ thisRulePropToModelMap.put("parser", ThisRulePropertyRef_parser.class);
+ }
+
+ public static final Map<String, Class<? extends RulePropertyRef>> rulePropToModelMap =
+ new HashMap<String, Class<? extends RulePropertyRef>>();
+ static {
+ rulePropToModelMap.put("start", RulePropertyRef_start.class);
+ rulePropToModelMap.put("stop", RulePropertyRef_stop.class);
+ rulePropToModelMap.put("text", RulePropertyRef_text.class);
+ rulePropToModelMap.put("ctx", RulePropertyRef_ctx.class);
+ rulePropToModelMap.put("parser", RulePropertyRef_parser.class);
+ }
+
+ public static final Map<String, Class<? extends TokenPropertyRef>> tokenPropToModelMap =
+ new HashMap<String, Class<? extends TokenPropertyRef>>();
+ static {
+ tokenPropToModelMap.put("text", TokenPropertyRef_text.class);
+ tokenPropToModelMap.put("type", TokenPropertyRef_type.class);
+ tokenPropToModelMap.put("line", TokenPropertyRef_line.class);
+ tokenPropToModelMap.put("index", TokenPropertyRef_index.class);
+ tokenPropToModelMap.put("pos", TokenPropertyRef_pos.class);
+ tokenPropToModelMap.put("channel", TokenPropertyRef_channel.class);
+ tokenPropToModelMap.put("int", TokenPropertyRef_int.class);
+ }
+
+ CodeGenerator gen;
+ ActionAST node;
+ RuleFunction rf;
+ List<ActionChunk> chunks = new ArrayList<ActionChunk>();
+ OutputModelFactory factory;
+ StructDecl nodeContext;
+
+ public ActionTranslator(OutputModelFactory factory, ActionAST node) {
+ this.factory = factory;
+ this.node = node;
+ this.gen = factory.getGenerator();
+ }
+
+ public static String toString(List<ActionChunk> chunks) {
+ StringBuilder buf = new StringBuilder();
+ for (ActionChunk c : chunks) buf.append(c.toString());
+ return buf.toString();
+ }
+
+ public static List<ActionChunk> translateAction(OutputModelFactory factory,
+ RuleFunction rf,
+ Token tokenWithinAction,
+ ActionAST node)
+ {
+ String action = tokenWithinAction.getText();
+ if ( action.charAt(0)=='{' ) {
+ int firstCurly = action.indexOf('{');
+ int lastCurly = action.lastIndexOf('}');
+ if ( firstCurly>=0 && lastCurly>=0 ) {
+ action = action.substring(firstCurly+1, lastCurly); // trim {...}
+ }
+ }
+ return translateActionChunk(factory, rf, action, node);
+ }
+
+ public static List<ActionChunk> translateActionChunk(OutputModelFactory factory,
+ RuleFunction rf,
+ String action,
+ ActionAST node)
+ {
+ Token tokenWithinAction = node.token;
+ ActionTranslator translator = new ActionTranslator(factory, node);
+ translator.rf = rf;
+ factory.getGrammar().tool.log("action-translator", "translate " + action);
+ String altLabel = node.getAltLabel();
+ if ( rf!=null ) translator.nodeContext = rf.ruleCtx;
+ if ( altLabel!=null ) translator.nodeContext = rf.altLabelCtxs.get(altLabel);
+ ANTLRStringStream in = new ANTLRStringStream(action);
+ in.setLine(tokenWithinAction.getLine());
+ in.setCharPositionInLine(tokenWithinAction.getCharPositionInLine());
+ ActionSplitter trigger = new ActionSplitter(in, translator);
+ // forces eval, triggers listener methods
+ trigger.getActionTokens();
+ return translator.chunks;
+ }
+
+ @Override
+ public void attr(String expr, Token x) {
+ gen.g.tool.log("action-translator", "attr "+x);
+ Attribute a = node.resolver.resolveToAttribute(x.getText(), node);
+ if ( a!=null ) {
+ switch ( a.dict.type ) {
+ case ARG: chunks.add(new ArgRef(nodeContext,x.getText())); break;
+ case RET: chunks.add(new RetValueRef(rf.ruleCtx, x.getText())); break;
+ case LOCAL: chunks.add(new LocalRef(nodeContext,x.getText())); break;
+ case PREDEFINED_RULE: chunks.add(getRulePropertyRef(x)); break;
+ }
+ }
+ if ( node.resolver.resolvesToToken(x.getText(), node) ) {
+ chunks.add(new TokenRef(nodeContext,getTokenLabel(x.getText()))); // $label
+ return;
+ }
+ if ( node.resolver.resolvesToLabel(x.getText(), node) ) {
+ chunks.add(new LabelRef(nodeContext,getTokenLabel(x.getText()))); // $x for x=ID etc...
+ return;
+ }
+ if ( node.resolver.resolvesToListLabel(x.getText(), node) ) {
+ chunks.add(new ListLabelRef(nodeContext,x.getText())); // $ids for ids+=ID etc...
+ return;
+ }
+ Rule r = factory.getGrammar().getRule(x.getText());
+ if ( r!=null ) {
+ chunks.add(new LabelRef(nodeContext,getRuleLabel(x.getText()))); // $r for r rule ref
+ }
+ }
+
+ @Override
+ public void qualifiedAttr(String expr, Token x, Token y) {
+ gen.g.tool.log("action-translator", "qattr "+x+"."+y);
+ if ( node.resolver.resolveToAttribute(x.getText(), node)!=null ) {
+ // must be a member access to a predefined attribute like $ctx.foo
+ attr(expr, x);
+ chunks.add(new ActionText(nodeContext, "."+y.getText()));
+ return;
+ }
+ Attribute a = node.resolver.resolveToAttribute(x.getText(), y.getText(), node);
+ switch ( a.dict.type ) {
+ case ARG: chunks.add(new ArgRef(nodeContext,y.getText())); break; // has to be current rule
+ case RET:
+ if ( factory.getCurrentRuleFunction()!=null &&
+ factory.getCurrentRuleFunction().name.equals(x.getText()) )
+ {
+ chunks.add(new RetValueRef(rf.ruleCtx, y.getText())); break;
+ }
+ else {
+ chunks.add(new QRetValueRef(nodeContext, getRuleLabel(x.getText()), y.getText())); break;
+ }
+ case PREDEFINED_RULE:
+ if ( factory.getCurrentRuleFunction()!=null &&
+ factory.getCurrentRuleFunction().name.equals(x.getText()) )
+ {
+ chunks.add(getRulePropertyRef(y));
+ }
+ else {
+ chunks.add(getRulePropertyRef(x, y));
+ }
+ break;
+ case TOKEN:
+ chunks.add(getTokenPropertyRef(x, y));
+ break;
+ }
+ }
+
+ @Override
+ public void setAttr(String expr, Token x, Token rhs) {
+ gen.g.tool.log("action-translator", "setAttr "+x+" "+rhs);
+ List<ActionChunk> rhsChunks = translateActionChunk(factory,rf,rhs.getText(),node);
+ SetAttr s = new SetAttr(nodeContext, x.getText(), rhsChunks);
+ chunks.add(s);
+ }
+
+ @Override
+ public void nonLocalAttr(String expr, Token x, Token y) {
+ gen.g.tool.log("action-translator", "nonLocalAttr "+x+"::"+y);
+ Rule r = factory.getGrammar().getRule(x.getText());
+ chunks.add(new NonLocalAttrRef(nodeContext, x.getText(), y.getText(), r.index));
+ }
+
+ @Override
+ public void setNonLocalAttr(String expr, Token x, Token y, Token rhs) {
+ gen.g.tool.log("action-translator", "setNonLocalAttr "+x+"::"+y+"="+rhs);
+ Rule r = factory.getGrammar().getRule(x.getText());
+ List<ActionChunk> rhsChunks = translateActionChunk(factory,rf,rhs.getText(),node);
+ SetNonLocalAttr s = new SetNonLocalAttr(nodeContext, x.getText(), y.getText(), r.index, rhsChunks);
+ chunks.add(s);
+ }
+
+ @Override
+ public void text(String text) {
+ chunks.add(new ActionText(nodeContext,text));
+ }
+
+ TokenPropertyRef getTokenPropertyRef(Token x, Token y) {
+ try {
+ Class<? extends TokenPropertyRef> c = tokenPropToModelMap.get(y.getText());
+ Constructor<? extends TokenPropertyRef> ctor = c.getConstructor(StructDecl.class, String.class);
+ TokenPropertyRef ref =
+ ctor.newInstance(nodeContext, getTokenLabel(x.getText()));
+ return ref;
+ }
+ catch (Exception e) {
+ factory.getGrammar().tool.errMgr.toolError(ErrorType.INTERNAL_ERROR, e);
+ }
+ return null;
+ }
+
+ // $text
+ RulePropertyRef getRulePropertyRef(Token prop) {
+ try {
+ Class<? extends RulePropertyRef> c = thisRulePropToModelMap.get(prop.getText());
+ Constructor<? extends RulePropertyRef> ctor = c.getConstructor(StructDecl.class, String.class);
+ RulePropertyRef ref =
+ ctor.newInstance(nodeContext, getRuleLabel(prop.getText()));
+ return ref;
+ }
+ catch (Exception e) {
+ factory.getGrammar().tool.errMgr.toolError(ErrorType.INTERNAL_ERROR, e);
+ }
+ return null;
+ }
+
+ RulePropertyRef getRulePropertyRef(Token x, Token prop) {
+ Grammar g = factory.getGrammar();
+ try {
+ Class<? extends RulePropertyRef> c = rulePropToModelMap.get(prop.getText());
+ Constructor<? extends RulePropertyRef> ctor = c.getConstructor(StructDecl.class, String.class);
+ RulePropertyRef ref =
+ ctor.newInstance(nodeContext, getRuleLabel(x.getText()));
+ return ref;
+ }
+ catch (Exception e) {
+ g.tool.errMgr.toolError(ErrorType.INTERNAL_ERROR, e, prop.getText());
+ }
+ return null;
+ }
+
+ public String getTokenLabel(String x) {
+ if ( node.resolver.resolvesToLabel(x, node) ) return x;
+ return factory.getGenerator().getTarget().getImplicitTokenLabel(x);
+ }
+
+ public String getRuleLabel(String x) {
+ if ( node.resolver.resolvesToLabel(x, node) ) return x;
+ return factory.getGenerator().getTarget().getImplicitRuleLabel(x);
+ }
+
+}
diff --git a/tool/src/org/antlr/v4/codegen/BlankOutputModelFactory.java b/tool/src/org/antlr/v4/codegen/BlankOutputModelFactory.java
new file mode 100644
index 0000000..bef03ac
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/BlankOutputModelFactory.java
@@ -0,0 +1,130 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen;
+
+import org.antlr.v4.codegen.model.Choice;
+import org.antlr.v4.codegen.model.CodeBlockForAlt;
+import org.antlr.v4.codegen.model.LabeledOp;
+import org.antlr.v4.codegen.model.Lexer;
+import org.antlr.v4.codegen.model.LexerFile;
+import org.antlr.v4.codegen.model.Parser;
+import org.antlr.v4.codegen.model.ParserFile;
+import org.antlr.v4.codegen.model.RuleFunction;
+import org.antlr.v4.codegen.model.SrcOp;
+import org.antlr.v4.runtime.misc.IntervalSet;
+import org.antlr.v4.tool.Alternative;
+import org.antlr.v4.tool.Rule;
+import org.antlr.v4.tool.ast.ActionAST;
+import org.antlr.v4.tool.ast.BlockAST;
+import org.antlr.v4.tool.ast.GrammarAST;
+
+import java.util.List;
+
+public abstract class BlankOutputModelFactory implements OutputModelFactory {
+ @Override
+ public ParserFile parserFile(String fileName) { return null; }
+
+ @Override
+ public Parser parser(ParserFile file) { return null; }
+
+ @Override
+ public RuleFunction rule(Rule r) { return null; }
+
+ @Override
+ public List<SrcOp> rulePostamble(RuleFunction function, Rule r) { return null; }
+
+ @Override
+ public LexerFile lexerFile(String fileName) { return null; }
+
+ @Override
+ public Lexer lexer(LexerFile file) { return null; }
+
+ // ALTERNATIVES / ELEMENTS
+
+ @Override
+ public CodeBlockForAlt alternative(Alternative alt, boolean outerMost) { return null; }
+
+ @Override
+ public CodeBlockForAlt finishAlternative(CodeBlockForAlt blk, List<SrcOp> ops) { return blk; }
+
+ @Override
+ public CodeBlockForAlt epsilon(Alternative alt, boolean outerMost) { return null; }
+
+ @Override
+ public List<SrcOp> ruleRef(GrammarAST ID, GrammarAST label, GrammarAST args) { return null; }
+
+ @Override
+ public List<SrcOp> tokenRef(GrammarAST ID, GrammarAST label, GrammarAST args) { return null; }
+
+ @Override
+ public List<SrcOp> stringRef(GrammarAST ID, GrammarAST label) { return tokenRef(ID, label, null); }
+
+ @Override
+ public List<SrcOp> set(GrammarAST setAST, GrammarAST label, boolean invert) { return null; }
+
+ @Override
+ public List<SrcOp> wildcard(GrammarAST ast, GrammarAST labelAST) { return null; }
+
+ // ACTIONS
+
+ @Override
+ public List<SrcOp> action(ActionAST ast) { return null; }
+
+ @Override
+ public List<SrcOp> sempred(ActionAST ast) { return null; }
+
+ // BLOCKS
+
+ @Override
+ public Choice getChoiceBlock(BlockAST blkAST, List<CodeBlockForAlt> alts, GrammarAST label) { return null; }
+
+ @Override
+ public Choice getEBNFBlock(GrammarAST ebnfRoot, List<CodeBlockForAlt> alts) { return null; }
+
+ @Override
+ public Choice getLL1ChoiceBlock(BlockAST blkAST, List<CodeBlockForAlt> alts) { return null; }
+
+ @Override
+ public Choice getComplexChoiceBlock(BlockAST blkAST, List<CodeBlockForAlt> alts) { return null; }
+
+ @Override
+ public Choice getLL1EBNFBlock(GrammarAST ebnfRoot, List<CodeBlockForAlt> alts) { return null; }
+
+ @Override
+ public Choice getComplexEBNFBlock(GrammarAST ebnfRoot, List<CodeBlockForAlt> alts) { return null; }
+
+ @Override
+ public List<SrcOp> getLL1Test(IntervalSet look, GrammarAST blkAST) { return null; }
+
+ @Override
+ public boolean needsImplicitLabel(GrammarAST ID, LabeledOp op) { return false; }
+}
+
diff --git a/tool/src/org/antlr/v4/codegen/CodeGenPipeline.java b/tool/src/org/antlr/v4/codegen/CodeGenPipeline.java
new file mode 100644
index 0000000..85b779d
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/CodeGenPipeline.java
@@ -0,0 +1,127 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen;
+
+import org.antlr.v4.parse.ANTLRParser;
+import org.antlr.v4.runtime.misc.IntervalSet;
+import org.antlr.v4.tool.ErrorType;
+import org.antlr.v4.tool.Grammar;
+import org.antlr.v4.tool.ast.GrammarAST;
+import org.stringtemplate.v4.ST;
+import org.stringtemplate.v4.gui.STViz;
+
+import java.util.List;
+
+public class CodeGenPipeline {
+ Grammar g;
+
+ public CodeGenPipeline(Grammar g) {
+ this.g = g;
+ }
+
+ public void process() {
+ if ( !CodeGenerator.targetExists(g.getOptionString("language")) ) return;
+
+ CodeGenerator gen = new CodeGenerator(g);
+ IntervalSet idTypes = new IntervalSet();
+ idTypes.add(ANTLRParser.ID);
+ idTypes.add(ANTLRParser.RULE_REF);
+ idTypes.add(ANTLRParser.TOKEN_REF);
+ List<GrammarAST> idNodes = g.ast.getNodesWithType(idTypes);
+ for (GrammarAST idNode : idNodes) {
+ if ( gen.getTarget().grammarSymbolCausesIssueInGeneratedCode(idNode) ) {
+ g.tool.errMgr.grammarError(ErrorType.USE_OF_BAD_WORD,
+ g.fileName, idNode.getToken(),
+ idNode.getText());
+ }
+ }
+
+ // all templates are generated in memory to report the most complete
+ // error information possible, but actually writing output files stops
+ // after the first error is reported
+ int errorCount = g.tool.errMgr.getNumErrors();
+
+ if ( g.isLexer() ) {
+ ST lexer = gen.generateLexer();
+ if (g.tool.errMgr.getNumErrors() == errorCount) {
+ writeRecognizer(lexer, gen);
+ }
+ }
+ else {
+ ST parser = gen.generateParser();
+ if (g.tool.errMgr.getNumErrors() == errorCount) {
+ writeRecognizer(parser, gen);
+ }
+ if ( g.tool.gen_listener ) {
+ ST listener = gen.generateListener();
+ if (g.tool.errMgr.getNumErrors() == errorCount) {
+ gen.writeListener(listener);
+ }
+ if (gen.getTarget().wantsBaseListener()) {
+ ST baseListener = gen.generateBaseListener();
+ if (g.tool.errMgr.getNumErrors() == errorCount) {
+ gen.writeBaseListener(baseListener);
+ }
+ }
+ }
+ if ( g.tool.gen_visitor ) {
+ ST visitor = gen.generateVisitor();
+ if (g.tool.errMgr.getNumErrors() == errorCount) {
+ gen.writeVisitor(visitor);
+ }
+ if (gen.getTarget().wantsBaseVisitor()) {
+ ST baseVisitor = gen.generateBaseVisitor();
+ if (g.tool.errMgr.getNumErrors() == errorCount) {
+ gen.writeBaseVisitor(baseVisitor);
+ }
+ }
+ }
+ gen.writeHeaderFile();
+ }
+ gen.writeVocabFile();
+ }
+
+ protected void writeRecognizer(ST template, CodeGenerator gen) {
+ if ( g.tool.launch_ST_inspector ) {
+ STViz viz = template.inspect();
+ if (g.tool.ST_inspector_wait_for_close) {
+ try {
+ viz.waitForClose();
+ }
+ catch (InterruptedException ex) {
+ g.tool.errMgr.toolError(ErrorType.INTERNAL_ERROR, ex);
+ }
+ }
+ }
+
+ gen.writeRecognizer(template);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/CodeGenerator.java b/tool/src/org/antlr/v4/codegen/CodeGenerator.java
new file mode 100644
index 0000000..e75a4f1
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/CodeGenerator.java
@@ -0,0 +1,302 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen;
+
+import org.antlr.v4.Tool;
+import org.antlr.v4.codegen.model.OutputModelObject;
+import org.antlr.v4.runtime.Token;
+import org.antlr.v4.tool.ErrorType;
+import org.antlr.v4.tool.Grammar;
+import org.stringtemplate.v4.AutoIndentWriter;
+import org.stringtemplate.v4.ST;
+import org.stringtemplate.v4.STGroup;
+import org.stringtemplate.v4.STWriter;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.lang.reflect.Constructor;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/** General controller for code gen. Can instantiate sub generator(s).
+ */
+public class CodeGenerator {
+ public static final String TEMPLATE_ROOT = "org/antlr/v4/tool/templates/codegen";
+ public static final String VOCAB_FILE_EXTENSION = ".tokens";
+ public static final String DEFAULT_LANGUAGE = "Java";
+ public static final String vocabFilePattern =
+ "<tokens.keys:{t | <t>=<tokens.(t)>\n}>" +
+ "<literals.keys:{t | <t>=<literals.(t)>\n}>";
+
+
+ public final Grammar g;
+
+ public final Tool tool;
+
+ public final String language;
+
+ private Target target;
+
+ public int lineWidth = 72;
+
+ private CodeGenerator(String language) {
+ this.g = null;
+ this.tool = null;
+ this.language = language;
+ }
+
+ public CodeGenerator(Grammar g) {
+ this(g.tool, g, g.getOptionString("language"));
+ }
+
+ public CodeGenerator(Tool tool, Grammar g, String language) {
+ this.g = g;
+ this.tool = tool;
+ this.language = language != null ? language : DEFAULT_LANGUAGE;
+ }
+
+ public static boolean targetExists(String language) {
+ String targetName = "org.antlr.v4.codegen.target."+language+"Target";
+ try {
+ Class<? extends Target> c = Class.forName(targetName).asSubclass(Target.class);
+ Constructor<? extends Target> ctor = c.getConstructor(CodeGenerator.class);
+ CodeGenerator gen = new CodeGenerator(language);
+ Target target = ctor.newInstance(gen);
+ return target.templatesExist();
+ }
+ catch (Exception e) { // ignore errors; we're detecting presence only
+ }
+ return false;
+ }
+
+
+ public Target getTarget() {
+ if ( target == null && targetExists(language) ) {
+ loadLanguageTarget(language);
+ }
+ return target;
+ }
+
+
+ public STGroup getTemplates() {
+ Target t = getTarget();
+ return t==null ? null : t.getTemplates();
+ }
+
+ protected void loadLanguageTarget(String language) {
+ String targetName = "org.antlr.v4.codegen.target."+language+"Target";
+ try {
+ Class<? extends Target> c = Class.forName(targetName).asSubclass(Target.class);
+ Constructor<? extends Target> ctor = c.getConstructor(CodeGenerator.class);
+ target = ctor.newInstance(this);
+ }
+ catch (Exception e) {
+ tool.errMgr.toolError(ErrorType.CANNOT_CREATE_TARGET_GENERATOR,
+ e,
+ targetName);
+ }
+ }
+
+ // CREATE TEMPLATES BY WALKING MODEL
+
+ private OutputModelController createController() {
+ OutputModelFactory factory = new ParserFactory(this);
+ OutputModelController controller = new OutputModelController(factory);
+ factory.setController(controller);
+ return controller;
+ }
+
+ private ST walk(OutputModelObject outputModel) {
+ OutputModelWalker walker = new OutputModelWalker(tool, getTemplates());
+ return walker.walk(outputModel);
+ }
+
+ public ST generateLexer() { return walk(createController().buildLexerOutputModel()); }
+ public ST generateParser() { return walk(createController().buildParserOutputModel()); }
+ public ST generateListener() { return walk(createController().buildListenerOutputModel()); }
+ public ST generateBaseListener() { return walk(createController().buildBaseListenerOutputModel()); }
+ public ST generateVisitor() { return walk(createController().buildVisitorOutputModel()); }
+ public ST generateBaseVisitor() { return walk(createController().buildBaseVisitorOutputModel()); }
+
+ /** Generate a token vocab file with all the token names/types. For example:
+ * ID=7
+ * FOR=8
+ * 'for'=8
+ *
+ * This is independent of the target language; used by antlr internally
+ */
+ ST getTokenVocabOutput() {
+ ST vocabFileST = new ST(vocabFilePattern);
+ Map<String,Integer> tokens = new LinkedHashMap<String,Integer>();
+ // make constants for the token names
+ for (String t : g.tokenNameToTypeMap.keySet()) {
+ int tokenType = g.tokenNameToTypeMap.get(t);
+ if ( tokenType>=Token.MIN_USER_TOKEN_TYPE) {
+ tokens.put(t, tokenType);
+ }
+ }
+ vocabFileST.add("tokens", tokens);
+
+ // now dump the strings
+ Map<String,Integer> literals = new LinkedHashMap<String,Integer>();
+ for (String literal : g.stringLiteralToTypeMap.keySet()) {
+ int tokenType = g.stringLiteralToTypeMap.get(literal);
+ if ( tokenType>=Token.MIN_USER_TOKEN_TYPE) {
+ literals.put(literal, tokenType);
+ }
+ }
+ vocabFileST.add("literals", literals);
+
+ return vocabFileST;
+ }
+
+ public void writeRecognizer(ST outputFileST) {
+ getTarget().genFile(g, outputFileST, getRecognizerFileName());
+ }
+
+ public void writeListener(ST outputFileST) {
+ getTarget().genFile(g, outputFileST, getListenerFileName());
+ }
+
+ public void writeBaseListener(ST outputFileST) {
+ getTarget().genFile(g, outputFileST, getBaseListenerFileName());
+ }
+
+ public void writeVisitor(ST outputFileST) {
+ getTarget().genFile(g, outputFileST, getVisitorFileName());
+ }
+
+ public void writeBaseVisitor(ST outputFileST) {
+ getTarget().genFile(g, outputFileST, getBaseVisitorFileName());
+ }
+
+ public void writeHeaderFile() {
+ String fileName = getHeaderFileName();
+ if ( fileName==null ) return;
+ if ( getTemplates().isDefined("headerFile") ) {
+ ST extST = getTemplates().getInstanceOf("headerFileExtension");
+ ST headerFileST = null;
+ // TODO: don't hide this header file generation here!
+ getTarget().genRecognizerHeaderFile(g, headerFileST, extST.render(lineWidth));
+ }
+ }
+
+ public void writeVocabFile() {
+ // write out the vocab interchange file; used by antlr,
+ // does not change per target
+ ST tokenVocabSerialization = getTokenVocabOutput();
+ String fileName = getVocabFileName();
+ if ( fileName!=null ) {
+ getTarget().genFile(g, tokenVocabSerialization, fileName);
+ }
+ }
+
+ public void write(ST code, String fileName) {
+ try {
+// long start = System.currentTimeMillis();
+ Writer w = tool.getOutputFileWriter(g, fileName);
+ STWriter wr = new AutoIndentWriter(w);
+ wr.setLineWidth(lineWidth);
+ code.write(wr);
+ w.close();
+// long stop = System.currentTimeMillis();
+ }
+ catch (IOException ioe) {
+ tool.errMgr.toolError(ErrorType.CANNOT_WRITE_FILE,
+ ioe,
+ fileName);
+ }
+ }
+
+ /** Generate TParser.java and TLexer.java from T.g4 if combined, else
+ * just use T.java as output regardless of type.
+ */
+ public String getRecognizerFileName() {
+ ST extST = getTemplates().getInstanceOf("codeFileExtension");
+ String recognizerName = g.getRecognizerName();
+ return recognizerName+extST.render();
+ }
+
+ /** A given grammar T, return the listener name such as
+ * TListener.java, if we're using the Java target.
+ */
+ public String getListenerFileName() {
+ assert g.name != null;
+ ST extST = getTemplates().getInstanceOf("codeFileExtension");
+ String listenerName = g.name + "Listener";
+ return listenerName+extST.render();
+ }
+
+ /** A given grammar T, return the visitor name such as
+ * TVisitor.java, if we're using the Java target.
+ */
+ public String getVisitorFileName() {
+ assert g.name != null;
+ ST extST = getTemplates().getInstanceOf("codeFileExtension");
+ String listenerName = g.name + "Visitor";
+ return listenerName+extST.render();
+ }
+
+ /** A given grammar T, return a blank listener implementation
+ * such as TBaseListener.java, if we're using the Java target.
+ */
+ public String getBaseListenerFileName() {
+ assert g.name != null;
+ ST extST = getTemplates().getInstanceOf("codeFileExtension");
+ String listenerName = g.name + "BaseListener";
+ return listenerName+extST.render();
+ }
+
+ /** A given grammar T, return a blank listener implementation
+ * such as TBaseListener.java, if we're using the Java target.
+ */
+ public String getBaseVisitorFileName() {
+ assert g.name != null;
+ ST extST = getTemplates().getInstanceOf("codeFileExtension");
+ String listenerName = g.name + "BaseVisitor";
+ return listenerName+extST.render();
+ }
+
+ /** What is the name of the vocab file generated for this grammar?
+ * Returns null if no .tokens file should be generated.
+ */
+ public String getVocabFileName() {
+ return g.name+VOCAB_FILE_EXTENSION;
+ }
+
+ public String getHeaderFileName() {
+ ST extST = getTemplates().getInstanceOf("headerFileExtension");
+ if ( extST==null ) return null;
+ String recognizerName = g.getRecognizerName();
+ return recognizerName+extST.render();
+ }
+
+}
diff --git a/tool/src/org/antlr/v4/codegen/CodeGeneratorExtension.java b/tool/src/org/antlr/v4/codegen/CodeGeneratorExtension.java
new file mode 100644
index 0000000..e07180e
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/CodeGeneratorExtension.java
@@ -0,0 +1,96 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen;
+
+
+import org.antlr.v4.codegen.model.Choice;
+import org.antlr.v4.codegen.model.CodeBlockForAlt;
+import org.antlr.v4.codegen.model.LabeledOp;
+import org.antlr.v4.codegen.model.Lexer;
+import org.antlr.v4.codegen.model.LexerFile;
+import org.antlr.v4.codegen.model.Parser;
+import org.antlr.v4.codegen.model.ParserFile;
+import org.antlr.v4.codegen.model.RuleFunction;
+import org.antlr.v4.codegen.model.SrcOp;
+import org.antlr.v4.tool.ast.GrammarAST;
+
+import java.util.List;
+
+/** Filter list of SrcOps and return; default is pass-through filter */
+public class CodeGeneratorExtension {
+ public OutputModelFactory factory;
+
+ public CodeGeneratorExtension(OutputModelFactory factory) {
+ this.factory = factory;
+ }
+
+ public ParserFile parserFile(ParserFile f) { return f; }
+
+ public Parser parser(Parser p) { return p; }
+
+ public LexerFile lexerFile(LexerFile f) { return f; }
+
+ public Lexer lexer(Lexer l) { return l; }
+
+ public RuleFunction rule(RuleFunction rf) { return rf; }
+
+ public List<SrcOp> rulePostamble(List<SrcOp> ops) { return ops; }
+
+ public CodeBlockForAlt alternative(CodeBlockForAlt blk, boolean outerMost) { return blk; }
+
+ public CodeBlockForAlt finishAlternative(CodeBlockForAlt blk, boolean outerMost) { return blk; }
+
+ public CodeBlockForAlt epsilon(CodeBlockForAlt blk) { return blk; }
+
+ public List<SrcOp> ruleRef(List<SrcOp> ops) { return ops; }
+
+ public List<SrcOp> tokenRef(List<SrcOp> ops) { return ops; }
+
+ public List<SrcOp> set(List<SrcOp> ops) { return ops; }
+
+ public List<SrcOp> stringRef(List<SrcOp> ops) { return ops; }
+
+ public List<SrcOp> wildcard(List<SrcOp> ops) { return ops; }
+
+ // ACTIONS
+
+ public List<SrcOp> action(List<SrcOp> ops) { return ops; }
+
+ public List<SrcOp> sempred(List<SrcOp> ops) { return ops; }
+
+ // BLOCKS
+
+ public Choice getChoiceBlock(Choice c) { return c; }
+
+ public Choice getEBNFBlock(Choice c) { return c; }
+
+ public boolean needsImplicitLabel(GrammarAST ID, LabeledOp op) { return false; }
+}
diff --git a/tool/src/org/antlr/v4/codegen/DefaultOutputModelFactory.java b/tool/src/org/antlr/v4/codegen/DefaultOutputModelFactory.java
new file mode 100644
index 0000000..901e439
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/DefaultOutputModelFactory.java
@@ -0,0 +1,127 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen;
+
+import org.antlr.v4.codegen.model.CodeBlockForOuterMostAlt;
+import org.antlr.v4.codegen.model.OutputModelObject;
+import org.antlr.v4.codegen.model.RuleFunction;
+import org.antlr.v4.codegen.model.SrcOp;
+import org.antlr.v4.codegen.model.decl.CodeBlock;
+import org.antlr.v4.codegen.model.decl.Decl;
+import org.antlr.v4.tool.Alternative;
+import org.antlr.v4.tool.Grammar;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+/** Create output objects for elements *within* rule functions except
+ * buildOutputModel() which builds outer/root model object and any
+ * objects such as RuleFunction that surround elements in rule
+ * functions.
+ */
+public abstract class DefaultOutputModelFactory extends BlankOutputModelFactory {
+ // Interface to outside world
+
+ public final Grammar g;
+
+ public final CodeGenerator gen;
+
+ public OutputModelController controller;
+
+ protected DefaultOutputModelFactory(CodeGenerator gen) {
+ this.gen = gen;
+ this.g = gen.g;
+ }
+
+ @Override
+ public void setController(OutputModelController controller) {
+ this.controller = controller;
+ }
+
+ @Override
+ public OutputModelController getController() {
+ return controller;
+ }
+
+ // Convenience methods
+
+
+ @Override
+ public Grammar getGrammar() { return g; }
+
+ @Override
+ public CodeGenerator getGenerator() { return gen; }
+
+ @Override
+ public OutputModelObject getRoot() { return controller.getRoot(); }
+
+ @Override
+ public RuleFunction getCurrentRuleFunction() { return controller.getCurrentRuleFunction(); }
+
+ @Override
+ public Alternative getCurrentOuterMostAlt() { return controller.getCurrentOuterMostAlt(); }
+
+ @Override
+ public CodeBlock getCurrentBlock() { return controller.getCurrentBlock(); }
+
+ @Override
+ public CodeBlockForOuterMostAlt getCurrentOuterMostAlternativeBlock() { return controller.getCurrentOuterMostAlternativeBlock(); }
+
+ @Override
+ public int getCodeBlockLevel() { return controller.codeBlockLevel; }
+
+ @Override
+ public int getTreeLevel() { return controller.treeLevel; }
+
+ // MISC
+
+
+ public static List<SrcOp> list(SrcOp... values) {
+ return new ArrayList<SrcOp>(Arrays.asList(values));
+ }
+
+
+ public static List<SrcOp> list(Collection<? extends SrcOp> values) {
+ return new ArrayList<SrcOp>(values);
+ }
+
+
+ public Decl getCurrentDeclForName(String name) {
+ if ( getCurrentBlock().locals==null ) return null;
+ for (Decl d : getCurrentBlock().locals.elements()) {
+ if ( d.name.equals(name) ) return d;
+ }
+ return null;
+ }
+
+}
diff --git a/tool/src/org/antlr/v4/codegen/LexerFactory.java b/tool/src/org/antlr/v4/codegen/LexerFactory.java
new file mode 100644
index 0000000..add1c8c
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/LexerFactory.java
@@ -0,0 +1,36 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen;
+
+/** */
+public class LexerFactory extends DefaultOutputModelFactory {
+ public LexerFactory(CodeGenerator gen) { super(gen); }
+}
diff --git a/tool/src/org/antlr/v4/codegen/OutputModelController.java b/tool/src/org/antlr/v4/codegen/OutputModelController.java
new file mode 100644
index 0000000..6b0d9db
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/OutputModelController.java
@@ -0,0 +1,500 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen;
+
+import org.antlr.runtime.tree.CommonTreeNodeStream;
+import org.antlr.v4.analysis.LeftRecursiveRuleAltInfo;
+import org.antlr.v4.codegen.model.Action;
+import org.antlr.v4.codegen.model.AltBlock;
+import org.antlr.v4.codegen.model.BaseListenerFile;
+import org.antlr.v4.codegen.model.BaseVisitorFile;
+import org.antlr.v4.codegen.model.Choice;
+import org.antlr.v4.codegen.model.CodeBlockForAlt;
+import org.antlr.v4.codegen.model.CodeBlockForOuterMostAlt;
+import org.antlr.v4.codegen.model.LabeledOp;
+import org.antlr.v4.codegen.model.LeftRecursiveRuleFunction;
+import org.antlr.v4.codegen.model.Lexer;
+import org.antlr.v4.codegen.model.LexerFile;
+import org.antlr.v4.codegen.model.ListenerFile;
+import org.antlr.v4.codegen.model.OutputModelObject;
+import org.antlr.v4.codegen.model.Parser;
+import org.antlr.v4.codegen.model.ParserFile;
+import org.antlr.v4.codegen.model.RuleActionFunction;
+import org.antlr.v4.codegen.model.RuleFunction;
+import org.antlr.v4.codegen.model.RuleSempredFunction;
+import org.antlr.v4.codegen.model.SrcOp;
+import org.antlr.v4.codegen.model.StarBlock;
+import org.antlr.v4.codegen.model.VisitorFile;
+import org.antlr.v4.codegen.model.decl.CodeBlock;
+import org.antlr.v4.misc.Utils;
+import org.antlr.v4.parse.ANTLRParser;
+import org.antlr.v4.parse.GrammarASTAdaptor;
+import org.antlr.v4.tool.Alternative;
+import org.antlr.v4.tool.ErrorType;
+import org.antlr.v4.tool.Grammar;
+import org.antlr.v4.tool.LeftRecursiveRule;
+import org.antlr.v4.tool.Rule;
+import org.antlr.v4.tool.ast.ActionAST;
+import org.antlr.v4.tool.ast.BlockAST;
+import org.antlr.v4.tool.ast.GrammarAST;
+import org.antlr.v4.tool.ast.PredAST;
+import org.stringtemplate.v4.ST;
+import org.stringtemplate.v4.STGroup;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Stack;
+
+/** This receives events from SourceGenTriggers.g and asks factory to do work.
+ * Then runs extensions in order on resulting SrcOps to get final list.
+ **/
+public class OutputModelController {
+ /** Who does the work? Doesn't have to be CoreOutputModelFactory. */
+ public OutputModelFactory delegate;
+
+ /** Post-processing CodeGeneratorExtension objects; done in order given. */
+ public List<CodeGeneratorExtension> extensions = new ArrayList<CodeGeneratorExtension>();
+
+ /** While walking code in rules, this is set to the tree walker that
+ * triggers actions.
+ */
+ public SourceGenTriggers walker;
+
+ /** Context set by the SourceGenTriggers.g */
+ public int codeBlockLevel = -1;
+ public int treeLevel = -1;
+ public OutputModelObject root; // normally ParserFile, LexerFile, ...
+ public Stack<RuleFunction> currentRule = new Stack<RuleFunction>();
+ public Alternative currentOuterMostAlt;
+ public CodeBlock currentBlock;
+ public CodeBlockForOuterMostAlt currentOuterMostAlternativeBlock;
+
+ public OutputModelController(OutputModelFactory factory) {
+ this.delegate = factory;
+ }
+
+ public void addExtension(CodeGeneratorExtension ext) { extensions.add(ext); }
+
+ /** Build a file with a parser containing rule functions. Use the
+ * controller as factory in SourceGenTriggers so it triggers codegen
+ * extensions too, not just the factory functions in this factory.
+ */
+ public OutputModelObject buildParserOutputModel() {
+ Grammar g = delegate.getGrammar();
+ CodeGenerator gen = delegate.getGenerator();
+ ParserFile file = parserFile(gen.getRecognizerFileName());
+ setRoot(file);
+ Parser parser = parser(file);
+ file.parser = parser;
+
+ for (Rule r : g.rules.values()) {
+ buildRuleFunction(parser, r);
+ }
+
+ return file;
+ }
+
+ public OutputModelObject buildLexerOutputModel() {
+ CodeGenerator gen = delegate.getGenerator();
+ LexerFile file = lexerFile(gen.getRecognizerFileName());
+ setRoot(file);
+ file.lexer = lexer(file);
+
+ Grammar g = delegate.getGrammar();
+ for (Rule r : g.rules.values()) {
+ buildLexerRuleActions(file.lexer, r);
+ }
+
+ return file;
+ }
+
+ public OutputModelObject buildListenerOutputModel() {
+ CodeGenerator gen = delegate.getGenerator();
+ return new ListenerFile(delegate, gen.getListenerFileName());
+ }
+
+ public OutputModelObject buildBaseListenerOutputModel() {
+ CodeGenerator gen = delegate.getGenerator();
+ return new BaseListenerFile(delegate, gen.getBaseListenerFileName());
+ }
+
+ public OutputModelObject buildVisitorOutputModel() {
+ CodeGenerator gen = delegate.getGenerator();
+ return new VisitorFile(delegate, gen.getVisitorFileName());
+ }
+
+ public OutputModelObject buildBaseVisitorOutputModel() {
+ CodeGenerator gen = delegate.getGenerator();
+ return new BaseVisitorFile(delegate, gen.getBaseVisitorFileName());
+ }
+
+ public ParserFile parserFile(String fileName) {
+ ParserFile f = delegate.parserFile(fileName);
+ for (CodeGeneratorExtension ext : extensions) f = ext.parserFile(f);
+ return f;
+ }
+
+ public Parser parser(ParserFile file) {
+ Parser p = delegate.parser(file);
+ for (CodeGeneratorExtension ext : extensions) p = ext.parser(p);
+ return p;
+ }
+
+ public LexerFile lexerFile(String fileName) {
+ return new LexerFile(delegate, fileName);
+ }
+
+ public Lexer lexer(LexerFile file) {
+ return new Lexer(delegate, file);
+ }
+
+ /** Create RuleFunction per rule and update sempreds,actions of parser
+ * output object with stuff found in r.
+ */
+ public void buildRuleFunction(Parser parser, Rule r) {
+ RuleFunction function = rule(r);
+ parser.funcs.add(function);
+ pushCurrentRule(function);
+ function.fillNamedActions(delegate, r);
+
+ if ( r instanceof LeftRecursiveRule ) {
+ buildLeftRecursiveRuleFunction((LeftRecursiveRule)r,
+ (LeftRecursiveRuleFunction)function);
+ }
+ else {
+ buildNormalRuleFunction(r, function);
+ }
+
+ Grammar g = getGrammar();
+ for (ActionAST a : r.actions) {
+ if ( a instanceof PredAST ) {
+ PredAST p = (PredAST)a;
+ RuleSempredFunction rsf = parser.sempredFuncs.get(r);
+ if ( rsf==null ) {
+ rsf = new RuleSempredFunction(delegate, r, function.ctxType);
+ parser.sempredFuncs.put(r, rsf);
+ }
+ rsf.actions.put(g.sempreds.get(p), new Action(delegate, p));
+ }
+ }
+
+ popCurrentRule();
+ }
+
+ public void buildLeftRecursiveRuleFunction(LeftRecursiveRule r, LeftRecursiveRuleFunction function) {
+ buildNormalRuleFunction(r, function);
+
+ // now inject code to start alts
+ CodeGenerator gen = delegate.getGenerator();
+ STGroup codegenTemplates = gen.getTemplates();
+
+ // pick out alt(s) for primaries
+ CodeBlockForOuterMostAlt outerAlt = (CodeBlockForOuterMostAlt)function.code.get(0);
+ List<CodeBlockForAlt> primaryAltsCode = new ArrayList<CodeBlockForAlt>();
+ SrcOp primaryStuff = outerAlt.ops.get(0);
+ if ( primaryStuff instanceof Choice ) {
+ Choice primaryAltBlock = (Choice) primaryStuff;
+ primaryAltsCode.addAll(primaryAltBlock.alts);
+ }
+ else { // just a single alt I guess; no block
+ primaryAltsCode.add((CodeBlockForAlt)primaryStuff);
+ }
+
+ // pick out alt(s) for op alts
+ StarBlock opAltStarBlock = (StarBlock)outerAlt.ops.get(1);
+ CodeBlockForAlt altForOpAltBlock = opAltStarBlock.alts.get(0);
+ List<CodeBlockForAlt> opAltsCode = new ArrayList<CodeBlockForAlt>();
+ SrcOp opStuff = altForOpAltBlock.ops.get(0);
+ if ( opStuff instanceof AltBlock ) {
+ AltBlock opAltBlock = (AltBlock)opStuff;
+ opAltsCode.addAll(opAltBlock.alts);
+ }
+ else { // just a single alt I guess; no block
+ opAltsCode.add((CodeBlockForAlt)opStuff);
+ }
+
+ // Insert code in front of each primary alt to create specialized ctx if there was a label
+ for (int i = 0; i < primaryAltsCode.size(); i++) {
+ LeftRecursiveRuleAltInfo altInfo = r.recPrimaryAlts.get(i);
+ if ( altInfo.altLabel==null ) continue;
+ ST altActionST = codegenTemplates.getInstanceOf("recRuleReplaceContext");
+ altActionST.add("ctxName", Utils.capitalize(altInfo.altLabel));
+ Action altAction =
+ new Action(delegate, function.altLabelCtxs.get(altInfo.altLabel), altActionST);
+ CodeBlockForAlt alt = primaryAltsCode.get(i);
+ alt.insertOp(0, altAction);
+ }
+
+ // Insert code to set ctx.stop after primary block and before op * loop
+ ST setStopTokenAST = codegenTemplates.getInstanceOf("recRuleSetStopToken");
+ Action setStopTokenAction = new Action(delegate, function.ruleCtx, setStopTokenAST);
+ outerAlt.insertOp(1, setStopTokenAction);
+
+ // Insert code to set _prevctx at start of * loop
+ ST setPrevCtx = codegenTemplates.getInstanceOf("recRuleSetPrevCtx");
+ Action setPrevCtxAction = new Action(delegate, function.ruleCtx, setPrevCtx);
+ opAltStarBlock.addIterationOp(setPrevCtxAction);
+
+ // Insert code in front of each op alt to create specialized ctx if there was an alt label
+ for (int i = 0; i < opAltsCode.size(); i++) {
+ ST altActionST;
+ LeftRecursiveRuleAltInfo altInfo = r.recOpAlts.getElement(i);
+ String templateName;
+ if ( altInfo.altLabel!=null ) {
+ templateName = "recRuleLabeledAltStartAction";
+ altActionST = codegenTemplates.getInstanceOf(templateName);
+ altActionST.add("currentAltLabel", altInfo.altLabel);
+ }
+ else {
+ templateName = "recRuleAltStartAction";
+ altActionST = codegenTemplates.getInstanceOf(templateName);
+ altActionST.add("ctxName", Utils.capitalize(r.name));
+ }
+ altActionST.add("ruleName", r.name);
+ // add label of any lr ref we deleted
+ altActionST.add("label", altInfo.leftRecursiveRuleRefLabel);
+ if (altActionST.impl.formalArguments.containsKey("isListLabel")) {
+ altActionST.add("isListLabel", altInfo.isListLabel);
+ }
+ else if (altInfo.isListLabel) {
+ delegate.getGenerator().tool.errMgr.toolError(ErrorType.CODE_TEMPLATE_ARG_ISSUE, templateName, "isListLabel");
+ }
+ Action altAction =
+ new Action(delegate, function.altLabelCtxs.get(altInfo.altLabel), altActionST);
+ CodeBlockForAlt alt = opAltsCode.get(i);
+ alt.insertOp(0, altAction);
+ }
+ }
+
+ public void buildNormalRuleFunction(Rule r, RuleFunction function) {
+ CodeGenerator gen = delegate.getGenerator();
+ // TRIGGER factory functions for rule alts, elements
+ GrammarASTAdaptor adaptor = new GrammarASTAdaptor(r.ast.token.getInputStream());
+ GrammarAST blk = (GrammarAST)r.ast.getFirstChildWithType(ANTLRParser.BLOCK);
+ CommonTreeNodeStream nodes = new CommonTreeNodeStream(adaptor,blk);
+ walker = new SourceGenTriggers(nodes, this);
+ try {
+ // walk AST of rule alts/elements
+ function.code = DefaultOutputModelFactory.list(walker.block(null, null));
+ function.hasLookaheadBlock = walker.hasLookaheadBlock;
+ }
+ catch (org.antlr.runtime.RecognitionException e){
+ e.printStackTrace(System.err);
+ }
+
+ function.ctxType = gen.getTarget().getRuleFunctionContextStructName(function);
+
+ function.postamble = rulePostamble(function, r);
+ }
+
+ public void buildLexerRuleActions(Lexer lexer, final Rule r) {
+ if (r.actions.isEmpty()) {
+ return;
+ }
+
+ CodeGenerator gen = delegate.getGenerator();
+ Grammar g = delegate.getGrammar();
+ String ctxType = gen.getTarget().getRuleFunctionContextStructName(r);
+ RuleActionFunction raf = lexer.actionFuncs.get(r);
+ if ( raf==null ) {
+ raf = new RuleActionFunction(delegate, r, ctxType);
+ }
+
+ for (ActionAST a : r.actions) {
+ if ( a instanceof PredAST ) {
+ PredAST p = (PredAST)a;
+ RuleSempredFunction rsf = lexer.sempredFuncs.get(r);
+ if ( rsf==null ) {
+ rsf = new RuleSempredFunction(delegate, r, ctxType);
+ lexer.sempredFuncs.put(r, rsf);
+ }
+ rsf.actions.put(g.sempreds.get(p), new Action(delegate, p));
+ }
+ else if ( a.getType()== ANTLRParser.ACTION ) {
+ raf.actions.put(g.lexerActions.get(a), new Action(delegate, a));
+ }
+ }
+
+ if (!raf.actions.isEmpty() && !lexer.actionFuncs.containsKey(r)) {
+ // only add to lexer if the function actually contains actions
+ lexer.actionFuncs.put(r, raf);
+ }
+ }
+
+ public RuleFunction rule(Rule r) {
+ RuleFunction rf = delegate.rule(r);
+ for (CodeGeneratorExtension ext : extensions) rf = ext.rule(rf);
+ return rf;
+ }
+
+ public List<SrcOp> rulePostamble(RuleFunction function, Rule r) {
+ List<SrcOp> ops = delegate.rulePostamble(function, r);
+ for (CodeGeneratorExtension ext : extensions) ops = ext.rulePostamble(ops);
+ return ops;
+ }
+
+ public Grammar getGrammar() { return delegate.getGrammar(); }
+
+ public CodeGenerator getGenerator() { return delegate.getGenerator(); }
+
+ public CodeBlockForAlt alternative(Alternative alt, boolean outerMost) {
+ CodeBlockForAlt blk = delegate.alternative(alt, outerMost);
+ if ( outerMost ) {
+ currentOuterMostAlternativeBlock = (CodeBlockForOuterMostAlt)blk;
+ }
+ for (CodeGeneratorExtension ext : extensions) blk = ext.alternative(blk, outerMost);
+ return blk;
+ }
+
+ public CodeBlockForAlt finishAlternative(CodeBlockForAlt blk, List<SrcOp> ops,
+ boolean outerMost)
+ {
+ blk = delegate.finishAlternative(blk, ops);
+ for (CodeGeneratorExtension ext : extensions) blk = ext.finishAlternative(blk, outerMost);
+ return blk;
+ }
+
+ public List<SrcOp> ruleRef(GrammarAST ID, GrammarAST label, GrammarAST args) {
+ List<SrcOp> ops = delegate.ruleRef(ID, label, args);
+ for (CodeGeneratorExtension ext : extensions) {
+ ops = ext.ruleRef(ops);
+ }
+ return ops;
+ }
+
+ public List<SrcOp> tokenRef(GrammarAST ID, GrammarAST label, GrammarAST args)
+ {
+ List<SrcOp> ops = delegate.tokenRef(ID, label, args);
+ for (CodeGeneratorExtension ext : extensions) {
+ ops = ext.tokenRef(ops);
+ }
+ return ops;
+ }
+
+ public List<SrcOp> stringRef(GrammarAST ID, GrammarAST label) {
+ List<SrcOp> ops = delegate.stringRef(ID, label);
+ for (CodeGeneratorExtension ext : extensions) {
+ ops = ext.stringRef(ops);
+ }
+ return ops;
+ }
+
+ /** (A|B|C) possibly with ebnfRoot and label */
+ public List<SrcOp> set(GrammarAST setAST, GrammarAST labelAST, boolean invert) {
+ List<SrcOp> ops = delegate.set(setAST, labelAST, invert);
+ for (CodeGeneratorExtension ext : extensions) {
+ ops = ext.set(ops);
+ }
+ return ops;
+ }
+
+ public CodeBlockForAlt epsilon(Alternative alt, boolean outerMost) {
+ CodeBlockForAlt blk = delegate.epsilon(alt, outerMost);
+ for (CodeGeneratorExtension ext : extensions) blk = ext.epsilon(blk);
+ return blk;
+ }
+
+ public List<SrcOp> wildcard(GrammarAST ast, GrammarAST labelAST) {
+ List<SrcOp> ops = delegate.wildcard(ast, labelAST);
+ for (CodeGeneratorExtension ext : extensions) {
+ ops = ext.set(ops);
+ }
+ return ops;
+ }
+
+ public List<SrcOp> action(ActionAST ast) {
+ List<SrcOp> ops = delegate.action(ast);
+ for (CodeGeneratorExtension ext : extensions) ops = ext.action(ops);
+ return ops;
+ }
+
+ public List<SrcOp> sempred(ActionAST ast) {
+ List<SrcOp> ops = delegate.sempred(ast);
+ for (CodeGeneratorExtension ext : extensions) ops = ext.sempred(ops);
+ return ops;
+ }
+
+ public Choice getChoiceBlock(BlockAST blkAST, List<CodeBlockForAlt> alts, GrammarAST label) {
+ Choice c = delegate.getChoiceBlock(blkAST, alts, label);
+ for (CodeGeneratorExtension ext : extensions) c = ext.getChoiceBlock(c);
+ return c;
+ }
+
+ public Choice getEBNFBlock(GrammarAST ebnfRoot, List<CodeBlockForAlt> alts) {
+ Choice c = delegate.getEBNFBlock(ebnfRoot, alts);
+ for (CodeGeneratorExtension ext : extensions) c = ext.getEBNFBlock(c);
+ return c;
+ }
+
+ public boolean needsImplicitLabel(GrammarAST ID, LabeledOp op) {
+ boolean needs = delegate.needsImplicitLabel(ID, op);
+ for (CodeGeneratorExtension ext : extensions) needs |= ext.needsImplicitLabel(ID, op);
+ return needs;
+ }
+
+ public OutputModelObject getRoot() { return root; }
+
+ public void setRoot(OutputModelObject root) { this.root = root; }
+
+ public RuleFunction getCurrentRuleFunction() {
+ if ( !currentRule.isEmpty() ) return currentRule.peek();
+ return null;
+ }
+
+ public void pushCurrentRule(RuleFunction r) { currentRule.push(r); }
+
+ public RuleFunction popCurrentRule() {
+ if ( !currentRule.isEmpty() ) return currentRule.pop();
+ return null;
+ }
+
+ public Alternative getCurrentOuterMostAlt() { return currentOuterMostAlt; }
+
+ public void setCurrentOuterMostAlt(Alternative currentOuterMostAlt) { this.currentOuterMostAlt = currentOuterMostAlt; }
+
+ public void setCurrentBlock(CodeBlock blk) {
+ currentBlock = blk;
+ }
+
+ public CodeBlock getCurrentBlock() {
+ return currentBlock;
+ }
+
+ public void setCurrentOuterMostAlternativeBlock(CodeBlockForOuterMostAlt currentOuterMostAlternativeBlock) {
+ this.currentOuterMostAlternativeBlock = currentOuterMostAlternativeBlock;
+ }
+
+ public CodeBlockForOuterMostAlt getCurrentOuterMostAlternativeBlock() {
+ return currentOuterMostAlternativeBlock;
+ }
+
+ public int getCodeBlockLevel() { return codeBlockLevel; }
+}
diff --git a/tool/src/org/antlr/v4/codegen/OutputModelFactory.java b/tool/src/org/antlr/v4/codegen/OutputModelFactory.java
new file mode 100644
index 0000000..86f9ae0
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/OutputModelFactory.java
@@ -0,0 +1,130 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen;
+
+import org.antlr.v4.codegen.model.Choice;
+import org.antlr.v4.codegen.model.CodeBlockForAlt;
+import org.antlr.v4.codegen.model.CodeBlockForOuterMostAlt;
+import org.antlr.v4.codegen.model.LabeledOp;
+import org.antlr.v4.codegen.model.Lexer;
+import org.antlr.v4.codegen.model.LexerFile;
+import org.antlr.v4.codegen.model.OutputModelObject;
+import org.antlr.v4.codegen.model.Parser;
+import org.antlr.v4.codegen.model.ParserFile;
+import org.antlr.v4.codegen.model.RuleFunction;
+import org.antlr.v4.codegen.model.SrcOp;
+import org.antlr.v4.codegen.model.decl.CodeBlock;
+import org.antlr.v4.runtime.misc.IntervalSet;
+import org.antlr.v4.tool.Alternative;
+import org.antlr.v4.tool.Grammar;
+import org.antlr.v4.tool.Rule;
+import org.antlr.v4.tool.ast.ActionAST;
+import org.antlr.v4.tool.ast.BlockAST;
+import org.antlr.v4.tool.ast.GrammarAST;
+
+import java.util.List;
+
+public interface OutputModelFactory {
+ Grammar getGrammar();
+
+ CodeGenerator getGenerator();
+
+ void setController(OutputModelController controller);
+
+ OutputModelController getController();
+
+ ParserFile parserFile(String fileName);
+
+ Parser parser(ParserFile file);
+
+ LexerFile lexerFile(String fileName);
+
+ Lexer lexer(LexerFile file);
+
+ RuleFunction rule(Rule r);
+
+ List<SrcOp> rulePostamble(RuleFunction function, Rule r);
+
+ // ELEMENT TRIGGERS
+
+ CodeBlockForAlt alternative(Alternative alt, boolean outerMost);
+
+ CodeBlockForAlt finishAlternative(CodeBlockForAlt blk, List<SrcOp> ops);
+
+ CodeBlockForAlt epsilon(Alternative alt, boolean outerMost);
+
+ List<SrcOp> ruleRef(GrammarAST ID, GrammarAST label, GrammarAST args);
+
+ List<SrcOp> tokenRef(GrammarAST ID, GrammarAST label, GrammarAST args);
+
+ List<SrcOp> stringRef(GrammarAST ID, GrammarAST label);
+
+ List<SrcOp> set(GrammarAST setAST, GrammarAST label, boolean invert);
+
+ List<SrcOp> wildcard(GrammarAST ast, GrammarAST labelAST);
+
+ List<SrcOp> action(ActionAST ast);
+
+ List<SrcOp> sempred(ActionAST ast);
+
+ Choice getChoiceBlock(BlockAST blkAST, List<CodeBlockForAlt> alts, GrammarAST label);
+
+ Choice getEBNFBlock(GrammarAST ebnfRoot, List<CodeBlockForAlt> alts);
+
+ Choice getLL1ChoiceBlock(BlockAST blkAST, List<CodeBlockForAlt> alts);
+
+ Choice getComplexChoiceBlock(BlockAST blkAST, List<CodeBlockForAlt> alts);
+
+ Choice getLL1EBNFBlock(GrammarAST ebnfRoot, List<CodeBlockForAlt> alts);
+
+ Choice getComplexEBNFBlock(GrammarAST ebnfRoot, List<CodeBlockForAlt> alts);
+
+ List<SrcOp> getLL1Test(IntervalSet look, GrammarAST blkAST);
+
+ boolean needsImplicitLabel(GrammarAST ID, LabeledOp op);
+
+ // CONTEXT INFO
+
+ OutputModelObject getRoot();
+
+ RuleFunction getCurrentRuleFunction();
+
+ Alternative getCurrentOuterMostAlt();
+
+ CodeBlock getCurrentBlock();
+
+ CodeBlockForOuterMostAlt getCurrentOuterMostAlternativeBlock();
+
+ int getCodeBlockLevel();
+
+ int getTreeLevel();
+
+}
diff --git a/tool/src/org/antlr/v4/codegen/OutputModelWalker.java b/tool/src/org/antlr/v4/codegen/OutputModelWalker.java
new file mode 100644
index 0000000..8a03895
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/OutputModelWalker.java
@@ -0,0 +1,166 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen;
+
+import org.antlr.v4.Tool;
+import org.antlr.v4.codegen.model.ModelElement;
+import org.antlr.v4.codegen.model.OutputModelObject;
+import org.antlr.v4.tool.ErrorType;
+import org.stringtemplate.v4.ST;
+import org.stringtemplate.v4.STGroup;
+import org.stringtemplate.v4.compiler.FormalArgument;
+
+import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+
+/** Convert an output model tree to template hierarchy by walking
+ * the output model. Each output model object has a corresponding template
+ * of the same name. An output model object can have nested objects.
+ * We identify those nested objects by the list of arguments in the template
+ * definition. For example, here is the definition of the parser template:
+ *
+ * Parser(parser, scopes, funcs) ::= <<...>>
+ *
+ * The first template argument is always the output model object from which
+ * this walker will create the template. Any other arguments identify
+ * the field names within the output model object of nested model objects.
+ * So, in this case, template Parser is saying that output model object
+ * Parser has two fields the walker should chase called a scopes and funcs.
+ *
+ * This simple mechanism means we don't have to include code in every
+ * output model object that says how to create the corresponding template.
+ */
+public class OutputModelWalker {
+ Tool tool;
+ STGroup templates;
+
+ public OutputModelWalker(Tool tool,
+ STGroup templates)
+ {
+ this.tool = tool;
+ this.templates = templates;
+ }
+
+ public ST walk(OutputModelObject omo) {
+ // CREATE TEMPLATE FOR THIS OUTPUT OBJECT
+ Class<? extends OutputModelObject> cl = omo.getClass();
+ String templateName = cl.getSimpleName();
+ if ( templateName == null ) {
+ tool.errMgr.toolError(ErrorType.NO_MODEL_TO_TEMPLATE_MAPPING, cl.getSimpleName());
+ return new ST("["+templateName+" invalid]");
+ }
+ ST st = templates.getInstanceOf(templateName);
+ if ( st == null ) {
+ tool.errMgr.toolError(ErrorType.CODE_GEN_TEMPLATES_INCOMPLETE, templateName);
+ return new ST("["+templateName+" invalid]");
+ }
+ if ( st.impl.formalArguments == null ) {
+ tool.errMgr.toolError(ErrorType.CODE_TEMPLATE_ARG_ISSUE, templateName, "<none>");
+ return st;
+ }
+
+ Map<String,FormalArgument> formalArgs = st.impl.formalArguments;
+
+ // PASS IN OUTPUT MODEL OBJECT TO TEMPLATE AS FIRST ARG
+ Set<String> argNames = formalArgs.keySet();
+ Iterator<String> arg_it = argNames.iterator();
+ String modelArgName = arg_it.next(); // ordered so this is first arg
+ st.add(modelArgName, omo);
+
+ // COMPUTE STs FOR EACH NESTED MODEL OBJECT MARKED WITH @ModelElement AND MAKE ST ATTRIBUTE
+ Set<String> usedFieldNames = new HashSet<String>();
+ Field fields[] = cl.getFields();
+ for (Field fi : fields) {
+ ModelElement annotation = fi.getAnnotation(ModelElement.class);
+ if (annotation == null) {
+ continue;
+ }
+
+ String fieldName = fi.getName();
+
+ if (!usedFieldNames.add(fieldName)) {
+ tool.errMgr.toolError(ErrorType.INTERNAL_ERROR, "Model object " + omo.getClass().getSimpleName() + " has multiple fields named '" + fieldName + "'");
+ continue;
+ }
+
+ // Just don't set @ModelElement fields w/o formal arg in target ST
+ if ( formalArgs.get(fieldName)==null ) continue;
+
+ try {
+ Object o = fi.get(omo);
+ if ( o instanceof OutputModelObject ) { // SINGLE MODEL OBJECT?
+ OutputModelObject nestedOmo = (OutputModelObject)o;
+ ST nestedST = walk(nestedOmo);
+// System.out.println("set ModelElement "+fieldName+"="+nestedST+" in "+templateName);
+ st.add(fieldName, nestedST);
+ }
+ else if ( o instanceof Collection || o instanceof OutputModelObject[] ) {
+ // LIST OF MODEL OBJECTS?
+ if ( o instanceof OutputModelObject[] ) {
+ o = Arrays.asList((OutputModelObject[])o);
+ }
+ Collection<?> nestedOmos = (Collection<?>)o;
+ for (Object nestedOmo : nestedOmos) {
+ if ( nestedOmo==null ) continue;
+ ST nestedST = walk((OutputModelObject)nestedOmo);
+// System.out.println("set ModelElement "+fieldName+"="+nestedST+" in "+templateName);
+ st.add(fieldName, nestedST);
+ }
+ }
+ else if ( o instanceof Map ) {
+ Map<?, ?> nestedOmoMap = (Map<?, ?>)o;
+ Map<Object, ST> m = new LinkedHashMap<Object, ST>();
+ for (Map.Entry<?, ?> entry : nestedOmoMap.entrySet()) {
+ ST nestedST = walk((OutputModelObject)entry.getValue());
+// System.out.println("set ModelElement "+fieldName+"="+nestedST+" in "+templateName);
+ m.put(entry.getKey(), nestedST);
+ }
+ st.add(fieldName, m);
+ }
+ else if ( o!=null ) {
+ tool.errMgr.toolError(ErrorType.INTERNAL_ERROR, "not recognized nested model element: "+fieldName);
+ }
+ }
+ catch (IllegalAccessException iae) {
+ tool.errMgr.toolError(ErrorType.CODE_TEMPLATE_ARG_ISSUE, templateName, fieldName);
+ }
+ }
+ //st.impl.dump();
+ return st;
+ }
+
+}
diff --git a/tool/src/org/antlr/v4/codegen/ParserFactory.java b/tool/src/org/antlr/v4/codegen/ParserFactory.java
new file mode 100644
index 0000000..dfb33f5
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/ParserFactory.java
@@ -0,0 +1,367 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen;
+
+import org.antlr.v4.analysis.AnalysisPipeline;
+import org.antlr.v4.codegen.model.Action;
+import org.antlr.v4.codegen.model.AddToLabelList;
+import org.antlr.v4.codegen.model.AltBlock;
+import org.antlr.v4.codegen.model.Choice;
+import org.antlr.v4.codegen.model.CodeBlockForAlt;
+import org.antlr.v4.codegen.model.CodeBlockForOuterMostAlt;
+import org.antlr.v4.codegen.model.InvokeRule;
+import org.antlr.v4.codegen.model.LL1AltBlock;
+import org.antlr.v4.codegen.model.LL1OptionalBlock;
+import org.antlr.v4.codegen.model.LL1OptionalBlockSingleAlt;
+import org.antlr.v4.codegen.model.LL1PlusBlockSingleAlt;
+import org.antlr.v4.codegen.model.LL1StarBlockSingleAlt;
+import org.antlr.v4.codegen.model.LabeledOp;
+import org.antlr.v4.codegen.model.LeftRecursiveRuleFunction;
+import org.antlr.v4.codegen.model.MatchNotSet;
+import org.antlr.v4.codegen.model.MatchSet;
+import org.antlr.v4.codegen.model.MatchToken;
+import org.antlr.v4.codegen.model.OptionalBlock;
+import org.antlr.v4.codegen.model.Parser;
+import org.antlr.v4.codegen.model.ParserFile;
+import org.antlr.v4.codegen.model.PlusBlock;
+import org.antlr.v4.codegen.model.RuleFunction;
+import org.antlr.v4.codegen.model.SemPred;
+import org.antlr.v4.codegen.model.SrcOp;
+import org.antlr.v4.codegen.model.StarBlock;
+import org.antlr.v4.codegen.model.TestSetInline;
+import org.antlr.v4.codegen.model.decl.Decl;
+import org.antlr.v4.codegen.model.decl.RuleContextDecl;
+import org.antlr.v4.codegen.model.decl.TokenDecl;
+import org.antlr.v4.codegen.model.decl.TokenListDecl;
+import org.antlr.v4.parse.ANTLRParser;
+import org.antlr.v4.runtime.atn.DecisionState;
+import org.antlr.v4.runtime.atn.PlusLoopbackState;
+import org.antlr.v4.runtime.atn.StarLoopEntryState;
+import org.antlr.v4.runtime.misc.IntervalSet;
+import org.antlr.v4.tool.Alternative;
+import org.antlr.v4.tool.LeftRecursiveRule;
+import org.antlr.v4.tool.Rule;
+import org.antlr.v4.tool.ast.ActionAST;
+import org.antlr.v4.tool.ast.BlockAST;
+import org.antlr.v4.tool.ast.GrammarAST;
+import org.antlr.v4.tool.ast.TerminalAST;
+
+import java.util.List;
+
+/** */
+public class ParserFactory extends DefaultOutputModelFactory {
+ public ParserFactory(CodeGenerator gen) { super(gen); }
+
+ @Override
+ public ParserFile parserFile(String fileName) {
+ return new ParserFile(this, fileName);
+ }
+
+ @Override
+ public Parser parser(ParserFile file) {
+ return new Parser(this, file);
+ }
+
+ @Override
+ public RuleFunction rule(Rule r) {
+ if ( r instanceof LeftRecursiveRule ) {
+ return new LeftRecursiveRuleFunction(this, (LeftRecursiveRule)r);
+ }
+ else {
+ RuleFunction rf = new RuleFunction(this, r);
+ return rf;
+ }
+ }
+
+ @Override
+ public CodeBlockForAlt epsilon(Alternative alt, boolean outerMost) {
+ return alternative(alt, outerMost);
+ }
+
+ @Override
+ public CodeBlockForAlt alternative(Alternative alt, boolean outerMost) {
+ if ( outerMost ) return new CodeBlockForOuterMostAlt(this, alt);
+ return new CodeBlockForAlt(this);
+ }
+
+ @Override
+ public CodeBlockForAlt finishAlternative(CodeBlockForAlt blk, List<SrcOp> ops) {
+ blk.ops = ops;
+ return blk;
+ }
+
+ @Override
+ public List<SrcOp> action(ActionAST ast) { return list(new Action(this, ast)); }
+
+ @Override
+ public List<SrcOp> sempred(ActionAST ast) { return list(new SemPred(this, ast)); }
+
+ @Override
+ public List<SrcOp> ruleRef(GrammarAST ID, GrammarAST label, GrammarAST args) {
+ InvokeRule invokeOp = new InvokeRule(this, ID, label);
+ // If no manual label and action refs as token/rule not label, we need to define implicit label
+ if ( controller.needsImplicitLabel(ID, invokeOp) ) defineImplicitLabel(ID, invokeOp);
+ AddToLabelList listLabelOp = getAddToListOpIfListLabelPresent(invokeOp, label);
+ return list(invokeOp, listLabelOp);
+ }
+
+ @Override
+ public List<SrcOp> tokenRef(GrammarAST ID, GrammarAST labelAST, GrammarAST args) {
+ MatchToken matchOp = new MatchToken(this, (TerminalAST) ID);
+ if ( labelAST!=null ) {
+ String label = labelAST.getText();
+ RuleFunction rf = getCurrentRuleFunction();
+ if ( labelAST.parent.getType() == ANTLRParser.PLUS_ASSIGN ) {
+ // add Token _X and List<Token> X decls
+ defineImplicitLabel(ID, matchOp); // adds _X
+ TokenListDecl l = getTokenListLabelDecl(label);
+ rf.addContextDecl(ID.getAltLabel(), l);
+ }
+ else {
+ Decl d = getTokenLabelDecl(label);
+ matchOp.labels.add(d);
+ rf.addContextDecl(ID.getAltLabel(), d);
+ }
+
+// Decl d = getTokenLabelDecl(label);
+// ((MatchToken)matchOp).labels.add(d);
+// getCurrentRuleFunction().addContextDecl(ID.getAltLabel(), d);
+// if ( labelAST.parent.getType() == ANTLRParser.PLUS_ASSIGN ) {
+// TokenListDecl l = getTokenListLabelDecl(label);
+// getCurrentRuleFunction().addContextDecl(ID.getAltLabel(), l);
+// }
+ }
+ if ( controller.needsImplicitLabel(ID, matchOp) ) defineImplicitLabel(ID, matchOp);
+ AddToLabelList listLabelOp = getAddToListOpIfListLabelPresent(matchOp, labelAST);
+ return list(matchOp, listLabelOp);
+ }
+
+ public Decl getTokenLabelDecl(String label) {
+ return new TokenDecl(this, label);
+ }
+
+ public TokenListDecl getTokenListLabelDecl(String label) {
+ return new TokenListDecl(this, gen.getTarget().getListLabel(label));
+ }
+
+ @Override
+ public List<SrcOp> set(GrammarAST setAST, GrammarAST labelAST, boolean invert) {
+ MatchSet matchOp;
+ if ( invert ) matchOp = new MatchNotSet(this, setAST);
+ else matchOp = new MatchSet(this, setAST);
+ if ( labelAST!=null ) {
+ String label = labelAST.getText();
+ RuleFunction rf = getCurrentRuleFunction();
+ if ( labelAST.parent.getType() == ANTLRParser.PLUS_ASSIGN ) {
+ defineImplicitLabel(setAST, matchOp);
+ TokenListDecl l = getTokenListLabelDecl(label);
+ rf.addContextDecl(setAST.getAltLabel(), l);
+ }
+ else {
+ Decl d = getTokenLabelDecl(label);
+ matchOp.labels.add(d);
+ rf.addContextDecl(setAST.getAltLabel(), d);
+ }
+ }
+ if ( controller.needsImplicitLabel(setAST, matchOp) ) defineImplicitLabel(setAST, matchOp);
+ AddToLabelList listLabelOp = getAddToListOpIfListLabelPresent(matchOp, labelAST);
+ return list(matchOp, listLabelOp);
+ }
+
+ @Override
+ public List<SrcOp> wildcard(GrammarAST ast, GrammarAST labelAST) {
+ Wildcard wild = new Wildcard(this, ast);
+ // TODO: dup with tokenRef
+ if ( labelAST!=null ) {
+ String label = labelAST.getText();
+ Decl d = getTokenLabelDecl(label);
+ wild.labels.add(d);
+ getCurrentRuleFunction().addContextDecl(ast.getAltLabel(), d);
+ if ( labelAST.parent.getType() == ANTLRParser.PLUS_ASSIGN ) {
+ TokenListDecl l = getTokenListLabelDecl(label);
+ getCurrentRuleFunction().addContextDecl(ast.getAltLabel(), l);
+ }
+ }
+ if ( controller.needsImplicitLabel(ast, wild) ) defineImplicitLabel(ast, wild);
+ AddToLabelList listLabelOp = getAddToListOpIfListLabelPresent(wild, labelAST);
+ return list(wild, listLabelOp);
+ }
+
+ @Override
+ public Choice getChoiceBlock(BlockAST blkAST, List<CodeBlockForAlt> alts, GrammarAST labelAST) {
+ int decision = ((DecisionState)blkAST.atnState).decision;
+ Choice c;
+ if ( !g.tool.force_atn && AnalysisPipeline.disjoint(g.decisionLOOK.get(decision)) ) {
+ c = getLL1ChoiceBlock(blkAST, alts);
+ }
+ else {
+ c = getComplexChoiceBlock(blkAST, alts);
+ }
+
+ if ( labelAST!=null ) { // for x=(...), define x or x_list
+ String label = labelAST.getText();
+ Decl d = getTokenLabelDecl(label);
+ c.label = d;
+ getCurrentRuleFunction().addContextDecl(labelAST.getAltLabel(), d);
+ if ( labelAST.parent.getType() == ANTLRParser.PLUS_ASSIGN ) {
+ String listLabel = gen.getTarget().getListLabel(label);
+ TokenListDecl l = new TokenListDecl(this, listLabel);
+ getCurrentRuleFunction().addContextDecl(labelAST.getAltLabel(), l);
+ }
+ }
+
+ return c;
+ }
+
+ @Override
+ public Choice getEBNFBlock(GrammarAST ebnfRoot, List<CodeBlockForAlt> alts) {
+ if (!g.tool.force_atn) {
+ int decision;
+ if ( ebnfRoot.getType()==ANTLRParser.POSITIVE_CLOSURE ) {
+ decision = ((PlusLoopbackState)ebnfRoot.atnState).decision;
+ }
+ else if ( ebnfRoot.getType()==ANTLRParser.CLOSURE ) {
+ decision = ((StarLoopEntryState)ebnfRoot.atnState).decision;
+ }
+ else {
+ decision = ((DecisionState)ebnfRoot.atnState).decision;
+ }
+
+ if ( AnalysisPipeline.disjoint(g.decisionLOOK.get(decision)) ) {
+ return getLL1EBNFBlock(ebnfRoot, alts);
+ }
+ }
+
+ return getComplexEBNFBlock(ebnfRoot, alts);
+ }
+
+ @Override
+ public Choice getLL1ChoiceBlock(BlockAST blkAST, List<CodeBlockForAlt> alts) {
+ return new LL1AltBlock(this, blkAST, alts);
+ }
+
+ @Override
+ public Choice getComplexChoiceBlock(BlockAST blkAST, List<CodeBlockForAlt> alts) {
+ return new AltBlock(this, blkAST, alts);
+ }
+
+ @Override
+ public Choice getLL1EBNFBlock(GrammarAST ebnfRoot, List<CodeBlockForAlt> alts) {
+ int ebnf = 0;
+ if ( ebnfRoot!=null ) ebnf = ebnfRoot.getType();
+ Choice c = null;
+ switch ( ebnf ) {
+ case ANTLRParser.OPTIONAL :
+ if ( alts.size()==1 ) c = new LL1OptionalBlockSingleAlt(this, ebnfRoot, alts);
+ else c = new LL1OptionalBlock(this, ebnfRoot, alts);
+ break;
+ case ANTLRParser.CLOSURE :
+ if ( alts.size()==1 ) c = new LL1StarBlockSingleAlt(this, ebnfRoot, alts);
+ else c = getComplexEBNFBlock(ebnfRoot, alts);
+ break;
+ case ANTLRParser.POSITIVE_CLOSURE :
+ if ( alts.size()==1 ) c = new LL1PlusBlockSingleAlt(this, ebnfRoot, alts);
+ else c = getComplexEBNFBlock(ebnfRoot, alts);
+ break;
+ }
+ return c;
+ }
+
+ @Override
+ public Choice getComplexEBNFBlock(GrammarAST ebnfRoot, List<CodeBlockForAlt> alts) {
+ int ebnf = 0;
+ if ( ebnfRoot!=null ) ebnf = ebnfRoot.getType();
+ Choice c = null;
+ switch ( ebnf ) {
+ case ANTLRParser.OPTIONAL :
+ c = new OptionalBlock(this, ebnfRoot, alts);
+ break;
+ case ANTLRParser.CLOSURE :
+ c = new StarBlock(this, ebnfRoot, alts);
+ break;
+ case ANTLRParser.POSITIVE_CLOSURE :
+ c = new PlusBlock(this, ebnfRoot, alts);
+ break;
+ }
+ return c;
+ }
+
+ @Override
+ public List<SrcOp> getLL1Test(IntervalSet look, GrammarAST blkAST) {
+ return list(new TestSetInline(this, blkAST, look, gen.getTarget().getInlineTestSetWordSize()));
+ }
+
+ @Override
+ public boolean needsImplicitLabel(GrammarAST ID, LabeledOp op) {
+ Alternative currentOuterMostAlt = getCurrentOuterMostAlt();
+ boolean actionRefsAsToken = currentOuterMostAlt.tokenRefsInActions.containsKey(ID.getText());
+ boolean actionRefsAsRule = currentOuterMostAlt.ruleRefsInActions.containsKey(ID.getText());
+ return op.getLabels().isEmpty() && (actionRefsAsToken || actionRefsAsRule);
+ }
+
+ // support
+
+ public void defineImplicitLabel(GrammarAST ast, LabeledOp op) {
+ Decl d;
+ if ( ast.getType()==ANTLRParser.SET || ast.getType()==ANTLRParser.WILDCARD ) {
+ String implLabel =
+ gen.getTarget().getImplicitSetLabel(String.valueOf(ast.token.getTokenIndex()));
+ d = getTokenLabelDecl(implLabel);
+ ((TokenDecl)d).isImplicit = true;
+ }
+ else if ( ast.getType()==ANTLRParser.RULE_REF ) { // a rule reference?
+ Rule r = g.getRule(ast.getText());
+ String implLabel = gen.getTarget().getImplicitRuleLabel(ast.getText());
+ String ctxName =
+ gen.getTarget().getRuleFunctionContextStructName(r);
+ d = new RuleContextDecl(this, implLabel, ctxName);
+ ((RuleContextDecl)d).isImplicit = true;
+ }
+ else {
+ String implLabel = gen.getTarget().getImplicitTokenLabel(ast.getText());
+ d = getTokenLabelDecl(implLabel);
+ ((TokenDecl)d).isImplicit = true;
+ }
+ op.getLabels().add(d);
+ // all labels must be in scope struct in case we exec action out of context
+ getCurrentRuleFunction().addContextDecl(ast.getAltLabel(), d);
+ }
+
+ public AddToLabelList getAddToListOpIfListLabelPresent(LabeledOp op, GrammarAST label) {
+ AddToLabelList labelOp = null;
+ if ( label!=null && label.parent.getType()==ANTLRParser.PLUS_ASSIGN ) {
+ String listLabel = gen.getTarget().getListLabel(label.getText());
+ labelOp = new AddToLabelList(this, listLabel, op.getLabels().get(0));
+ }
+ return labelOp;
+ }
+
+}
diff --git a/tool/src/org/antlr/v4/codegen/SourceGenTriggers.g b/tool/src/org/antlr/v4/codegen/SourceGenTriggers.g
new file mode 100644
index 0000000..de3154f
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/SourceGenTriggers.g
@@ -0,0 +1,198 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+tree grammar SourceGenTriggers;
+options {
+ language = Java;
+ tokenVocab = ANTLRParser;
+ ASTLabelType = GrammarAST;
+}
+
+@header {
+package org.antlr.v4.codegen;
+import org.antlr.v4.misc.Utils;
+import org.antlr.v4.codegen.model.*;
+import org.antlr.v4.codegen.model.decl.*;
+import org.antlr.v4.tool.*;
+import org.antlr.v4.tool.ast.*;
+import java.util.Collections;
+import java.util.Map;
+import java.util.HashMap;
+}
+
+@members {
+ public OutputModelController controller;
+ public boolean hasLookaheadBlock;
+ public SourceGenTriggers(TreeNodeStream input, OutputModelController controller) {
+ this(input);
+ this.controller = controller;
+ }
+}
+
+dummy : block[null, null] ;
+
+block[GrammarAST label, GrammarAST ebnfRoot] returns [List<? extends SrcOp> omos]
+ : ^( blk=BLOCK (^(OPTIONS .+))?
+ {List<CodeBlockForAlt> alts = new ArrayList<CodeBlockForAlt>();}
+ ( alternative {alts.add($alternative.altCodeBlock);} )+
+ )
+ {
+ if ( alts.size()==1 && ebnfRoot==null) return alts;
+ if ( ebnfRoot==null ) {
+ $omos = DefaultOutputModelFactory.list(controller.getChoiceBlock((BlockAST)$blk, alts, $label));
+ }
+ else {
+ Choice choice = controller.getEBNFBlock($ebnfRoot, alts);
+ hasLookaheadBlock |= choice instanceof PlusBlock || choice instanceof StarBlock;
+ $omos = DefaultOutputModelFactory.list(choice);
+ }
+ }
+ ;
+
+alternative returns [CodeBlockForAlt altCodeBlock, List<SrcOp> ops]
+@init {
+ boolean outerMost = inContext("RULE BLOCK");
+}
+@after {
+ controller.finishAlternative($altCodeBlock, $ops, outerMost);
+}
+ : a=alt[outerMost] {$altCodeBlock=$a.altCodeBlock; $ops=$a.ops;}
+ ;
+
+alt[boolean outerMost] returns [CodeBlockForAlt altCodeBlock, List<SrcOp> ops]
+@init {
+ // set alt if outer ALT only (the only ones with alt field set to Alternative object)
+ AltAST altAST = (AltAST)retval.start;
+ if ( outerMost ) controller.setCurrentOuterMostAlt(altAST.alt);
+}
+ : {
+ List<SrcOp> elems = new ArrayList<SrcOp>();
+ // TODO: shouldn't we pass $start to controller.alternative()?
+ $altCodeBlock = controller.alternative(controller.getCurrentOuterMostAlt(), outerMost);
+ $altCodeBlock.ops = $ops = elems;
+ controller.setCurrentBlock($altCodeBlock);
+ }
+ ^( ALT elementOptions? ( element {if ($element.omos!=null) elems.addAll($element.omos);} )+ )
+
+ | ^(ALT elementOptions? EPSILON)
+ {$altCodeBlock = controller.epsilon(controller.getCurrentOuterMostAlt(), outerMost);}
+ ;
+
+element returns [List<? extends SrcOp> omos]
+ : labeledElement {$omos = $labeledElement.omos;}
+ | atom[null,false] {$omos = $atom.omos;}
+ | subrule {$omos = $subrule.omos;}
+ | ACTION {$omos = controller.action((ActionAST)$ACTION);}
+ | SEMPRED {$omos = controller.sempred((ActionAST)$SEMPRED);}
+ | ^(ACTION elementOptions) {$omos = controller.action((ActionAST)$ACTION);}
+ | ^(SEMPRED elementOptions) {$omos = controller.sempred((ActionAST)$SEMPRED);}
+ ;
+
+labeledElement returns [List<? extends SrcOp> omos]
+ : ^(ASSIGN ID atom[$ID,false] ) {$omos = $atom.omos;}
+ | ^(PLUS_ASSIGN ID atom[$ID,false]) {$omos = $atom.omos;}
+ | ^(ASSIGN ID block[$ID,null] ) {$omos = $block.omos;}
+ | ^(PLUS_ASSIGN ID block[$ID,null]) {$omos = $block.omos;}
+ ;
+
+subrule returns [List<? extends SrcOp> omos]
+ : ^(OPTIONAL b=block[null,$OPTIONAL])
+ {
+ $omos = $block.omos;
+ }
+ | ( ^(op=CLOSURE b=block[null,null])
+ | ^(op=POSITIVE_CLOSURE b=block[null,null])
+ )
+ {
+ List<CodeBlockForAlt> alts = new ArrayList<CodeBlockForAlt>();
+ SrcOp blk = $b.omos.get(0);
+ CodeBlockForAlt alt = new CodeBlockForAlt(controller.delegate);
+ alt.addOp(blk);
+ alts.add(alt);
+ SrcOp loop = controller.getEBNFBlock($op, alts); // "star it"
+ hasLookaheadBlock |= loop instanceof PlusBlock || loop instanceof StarBlock;
+ $omos = DefaultOutputModelFactory.list(loop);
+ }
+ | block[null, null] {$omos = $block.omos;}
+ ;
+
+blockSet[GrammarAST label, boolean invert] returns [List<SrcOp> omos]
+ : ^(SET atom[label,invert]+) {$omos = controller.set($SET, $label, invert);}
+ ;
+
+/*
+setElement
+ : STRING_LITERAL
+ | TOKEN_REF
+ | ^(RANGE STRING_LITERAL STRING_LITERAL)
+ ;
+*/
+
+// TODO: combine ROOT/BANG into one then just make new op ref'ing return value of atom/terminal...
+// TODO: same for NOT
+atom[GrammarAST label, boolean invert] returns [List<SrcOp> omos]
+ : ^(NOT a=atom[$label, true]) {$omos = $a.omos;}
+ | range[label] {$omos = $range.omos;}
+ | ^(DOT ID terminal[$label])
+ | ^(DOT ID ruleref[$label])
+ | ^(WILDCARD .) {$omos = controller.wildcard($WILDCARD, $label);}
+ | WILDCARD {$omos = controller.wildcard($WILDCARD, $label);}
+ | terminal[label] {$omos = $terminal.omos;}
+ | ruleref[label] {$omos = $ruleref.omos;}
+ | blockSet[$label, invert] {$omos = $blockSet.omos;}
+ ;
+
+ruleref[GrammarAST label] returns [List<SrcOp> omos]
+ : ^(RULE_REF ARG_ACTION? elementOptions?) {$omos = controller.ruleRef($RULE_REF, $label, $ARG_ACTION);}
+ ;
+
+range[GrammarAST label] returns [List<SrcOp> omos]
+ : ^(RANGE a=STRING_LITERAL b=STRING_LITERAL)
+ ;
+
+terminal[GrammarAST label] returns [List<SrcOp> omos]
+ : ^(STRING_LITERAL .) {$omos = controller.stringRef($STRING_LITERAL, $label);}
+ | STRING_LITERAL {$omos = controller.stringRef($STRING_LITERAL, $label);}
+ | ^(TOKEN_REF ARG_ACTION .) {$omos = controller.tokenRef($TOKEN_REF, $label, $ARG_ACTION);}
+ | ^(TOKEN_REF .) {$omos = controller.tokenRef($TOKEN_REF, $label, null);}
+ | TOKEN_REF {$omos = controller.tokenRef($TOKEN_REF, $label, null);}
+ ;
+
+elementOptions
+ : ^(ELEMENT_OPTIONS elementOption+)
+ ;
+
+elementOption
+ : ID
+ | ^(ASSIGN ID ID)
+ | ^(ASSIGN ID STRING_LITERAL)
+ | ^(ASSIGN ID ACTION)
+ | ^(ASSIGN ID INT)
+ ;
diff --git a/tool/src/org/antlr/v4/codegen/Target.java b/tool/src/org/antlr/v4/codegen/Target.java
new file mode 100644
index 0000000..1f2d748
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/Target.java
@@ -0,0 +1,527 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen;
+
+import org.antlr.v4.Tool;
+import org.antlr.v4.codegen.model.RuleFunction;
+import org.antlr.v4.codegen.model.SerializedATN;
+import org.antlr.v4.misc.Utils;
+import org.antlr.v4.parse.ANTLRParser;
+import org.antlr.v4.runtime.RuntimeMetaData;
+import org.antlr.v4.runtime.Token;
+import org.antlr.v4.tool.ErrorType;
+import org.antlr.v4.tool.Grammar;
+import org.antlr.v4.tool.Rule;
+import org.antlr.v4.tool.ast.GrammarAST;
+import org.stringtemplate.v4.NumberRenderer;
+import org.stringtemplate.v4.ST;
+import org.stringtemplate.v4.STErrorListener;
+import org.stringtemplate.v4.STGroup;
+import org.stringtemplate.v4.STGroupFile;
+import org.stringtemplate.v4.StringRenderer;
+import org.stringtemplate.v4.misc.STMessage;
+
+/** */
+public abstract class Target {
+ /** For pure strings of Java 16-bit Unicode char, how can we display
+ * it in the target language as a literal. Useful for dumping
+ * predicates and such that may refer to chars that need to be escaped
+ * when represented as strings. Also, templates need to be escaped so
+ * that the target language can hold them as a string.
+ * <p/>
+ * I have defined (via the constructor) the set of typical escapes,
+ * but your {@link Target} subclass is free to alter the translated chars
+ * or add more definitions. This is non-static so each target can have
+ * a different set in memory at same time.
+ */
+ protected String[] targetCharValueEscape = new String[255];
+
+ private final CodeGenerator gen;
+ private final String language;
+ private STGroup templates;
+
+ protected Target(CodeGenerator gen, String language) {
+ targetCharValueEscape['\n'] = "\\n";
+ targetCharValueEscape['\r'] = "\\r";
+ targetCharValueEscape['\t'] = "\\t";
+ targetCharValueEscape['\b'] = "\\b";
+ targetCharValueEscape['\f'] = "\\f";
+ targetCharValueEscape['\\'] = "\\\\";
+ targetCharValueEscape['\''] = "\\'";
+ targetCharValueEscape['"'] = "\\\"";
+ this.gen = gen;
+ this.language = language;
+ }
+
+ public CodeGenerator getCodeGenerator() {
+ return gen;
+ }
+
+ public String getLanguage() {
+ return language;
+ }
+
+ /** ANTLR tool should check output templates / target are compatible with tool code generation.
+ * For now, a simple string match used on x.y of x.y.z scheme. We use a method to avoid mismatches
+ * between a template called VERSION. This value is checked against Tool.VERSION during load of templates.
+ *
+ * This additional method forces all targets 4.3 and beyond to add this method.
+ *
+ * @since 4.3
+ */
+ public abstract String getVersion();
+
+
+ public STGroup getTemplates() {
+ if (templates == null) {
+ String version = getVersion();
+ if ( version==null ||
+ !RuntimeMetaData.getMajorMinorVersion(version).equals(RuntimeMetaData.getMajorMinorVersion(Tool.VERSION)))
+ {
+ gen.tool.errMgr.toolError(ErrorType.INCOMPATIBLE_TOOL_AND_TEMPLATES, version, Tool.VERSION, language);
+ }
+ templates = loadTemplates();
+ }
+
+ return templates;
+ }
+
+ protected void genFile(Grammar g,
+ ST outputFileST,
+ String fileName)
+ {
+ getCodeGenerator().write(outputFileST, fileName);
+ }
+
+ protected void genListenerFile(Grammar g,
+ ST outputFileST)
+ {
+ String fileName = getCodeGenerator().getListenerFileName();
+ getCodeGenerator().write(outputFileST, fileName);
+ }
+
+ protected void genRecognizerHeaderFile(Grammar g,
+ ST headerFileST,
+ String extName) // e.g., ".h"
+ {
+ // no header file by default
+ }
+
+ /** Get a meaningful name for a token type useful during code generation.
+ * Literals without associated names are converted to the string equivalent
+ * of their integer values. Used to generate x==ID and x==34 type comparisons
+ * etc... Essentially we are looking for the most obvious way to refer
+ * to a token type in the generated code.
+ */
+ public String getTokenTypeAsTargetLabel(Grammar g, int ttype) {
+ String name = g.getTokenName(ttype);
+ // If name is not valid, return the token type instead
+ if ( Grammar.INVALID_TOKEN_NAME.equals(name) ) {
+ return String.valueOf(ttype);
+ }
+
+ return name;
+ }
+
+ public String[] getTokenTypesAsTargetLabels(Grammar g, int[] ttypes) {
+ String[] labels = new String[ttypes.length];
+ for (int i=0; i<ttypes.length; i++) {
+ labels[i] = getTokenTypeAsTargetLabel(g, ttypes[i]);
+ }
+ return labels;
+ }
+
+ /** Given a random string of Java unicode chars, return a new string with
+ * optionally appropriate quote characters for target language and possibly
+ * with some escaped characters. For example, if the incoming string has
+ * actual newline characters, the output of this method would convert them
+ * to the two char sequence \n for Java, C, C++, ... The new string has
+ * double-quotes around it as well. Example String in memory:
+ *
+ * a"[newlinechar]b'c[carriagereturnchar]d[tab]e\f
+ *
+ * would be converted to the valid Java s:
+ *
+ * "a\"\nb'c\rd\te\\f"
+ *
+ * or
+ *
+ * a\"\nb'c\rd\te\\f
+ *
+ * depending on the quoted arg.
+ */
+ public String getTargetStringLiteralFromString(String s, boolean quoted) {
+ if ( s==null ) {
+ return null;
+ }
+
+ StringBuilder buf = new StringBuilder();
+ if ( quoted ) {
+ buf.append('"');
+ }
+ for (int i=0; i<s.length(); i++) {
+ int c = s.charAt(i);
+ if ( c!='\'' && // don't escape single quotes in strings for java
+ c<targetCharValueEscape.length &&
+ targetCharValueEscape[c]!=null )
+ {
+ buf.append(targetCharValueEscape[c]);
+ }
+ else {
+ buf.append((char)c);
+ }
+ }
+ if ( quoted ) {
+ buf.append('"');
+ }
+ return buf.toString();
+ }
+
+ public String getTargetStringLiteralFromString(String s) {
+ return getTargetStringLiteralFromString(s, true);
+ }
+
+ /**
+ * <p>Convert from an ANTLR string literal found in a grammar file to an
+ * equivalent string literal in the target language.
+ *</p>
+ * <p>
+ * For Java, this is the translation {@code 'a\n"'} &rarr; {@code "a\n\""}.
+ * Expect single quotes around the incoming literal. Just flip the quotes
+ * and replace double quotes with {@code \"}.
+ * </p>
+ * <p>
+ * Note that we have decided to allow people to use '\"' without penalty, so
+ * we must build the target string in a loop as {@link String#replace}
+ * cannot handle both {@code \"} and {@code "} without a lot of messing
+ * around.
+ * </p>
+ */
+ public String getTargetStringLiteralFromANTLRStringLiteral(
+ CodeGenerator generator,
+ String literal,
+ boolean addQuotes)
+ {
+ StringBuilder sb = new StringBuilder();
+ String is = literal;
+
+ if ( addQuotes ) sb.append('"');
+
+ for (int i = 1; i < is.length() -1; i++) {
+ if (is.charAt(i) == '\\') {
+ // Anything escaped is what it is! We assume that
+ // people know how to escape characters correctly. However
+ // we catch anything that does not need an escape in Java (which
+ // is what the default implementation is dealing with and remove
+ // the escape. The C target does this for instance.
+ //
+ switch (is.charAt(i+1)) {
+ // Pass through any escapes that Java also needs
+ //
+ case '"':
+ case 'n':
+ case 'r':
+ case 't':
+ case 'b':
+ case 'f':
+ case '\\':
+ // Pass the escape through
+ sb.append('\\');
+ break;
+
+ case 'u': // Assume unnnn
+ // Pass the escape through as double \\
+ // so that Java leaves as \u0000 string not char
+ sb.append('\\');
+ sb.append('\\');
+ break;
+
+ default:
+ // Remove the escape by virtue of not adding it here
+ // Thus \' becomes ' and so on
+ break;
+ }
+
+ // Go past the \ character
+ i++;
+ } else {
+ // Characters that don't need \ in ANTLR 'strings' but do in Java
+ if (is.charAt(i) == '"') {
+ // We need to escape " in Java
+ sb.append('\\');
+ }
+ }
+ // Add in the next character, which may have been escaped
+ sb.append(is.charAt(i));
+ }
+
+ if ( addQuotes ) sb.append('"');
+
+ return sb.toString();
+ }
+
+ /** Assume 16-bit char */
+ public String encodeIntAsCharEscape(int v) {
+ if (v < Character.MIN_VALUE || v > Character.MAX_VALUE) {
+ throw new IllegalArgumentException(String.format("Cannot encode the specified value: %d", v));
+ }
+
+ if (v >= 0 && v < targetCharValueEscape.length && targetCharValueEscape[v] != null) {
+ return targetCharValueEscape[v];
+ }
+
+ if (v >= 0x20 && v < 127 && (!Character.isDigit(v) || v == '8' || v == '9')) {
+ return String.valueOf((char)v);
+ }
+
+ if ( v>=0 && v<=127 ) {
+ String oct = Integer.toOctalString(v);
+ return "\\"+ oct;
+ }
+
+ String hex = Integer.toHexString(v|0x10000).substring(1,5);
+ return "\\u"+hex;
+ }
+
+ public String getLoopLabel(GrammarAST ast) {
+ return "loop"+ ast.token.getTokenIndex();
+ }
+
+ public String getLoopCounter(GrammarAST ast) {
+ return "cnt"+ ast.token.getTokenIndex();
+ }
+
+ public String getListLabel(String label) {
+ ST st = getTemplates().getInstanceOf("ListLabelName");
+ st.add("label", label);
+ return st.render();
+ }
+
+ public String getRuleFunctionContextStructName(Rule r) {
+ if ( r.g.isLexer() ) {
+ return getTemplates().getInstanceOf("LexerRuleContext").render();
+ }
+ return Utils.capitalize(r.name)+getTemplates().getInstanceOf("RuleContextNameSuffix").render();
+ }
+
+ public String getAltLabelContextStructName(String label) {
+ return Utils.capitalize(label)+getTemplates().getInstanceOf("RuleContextNameSuffix").render();
+ }
+
+ /** If we know which actual function, we can provide the actual ctx type.
+ * This will contain implicit labels etc... From outside, though, we
+ * see only ParserRuleContext unless there are externally visible stuff
+ * like args, locals, explicit labels, etc...
+ */
+ public String getRuleFunctionContextStructName(RuleFunction function) {
+ Rule r = function.rule;
+ if ( r.g.isLexer() ) {
+ return getTemplates().getInstanceOf("LexerRuleContext").render();
+ }
+ return Utils.capitalize(r.name)+getTemplates().getInstanceOf("RuleContextNameSuffix").render();
+ }
+
+ // should be same for all refs to same token like ctx.ID within single rule function
+ // for literals like 'while', we gen _s<ttype>
+ public String getImplicitTokenLabel(String tokenName) {
+ ST st = getTemplates().getInstanceOf("ImplicitTokenLabel");
+ int ttype = getCodeGenerator().g.getTokenType(tokenName);
+ if ( tokenName.startsWith("'") ) {
+ return "s"+ttype;
+ }
+ String text = getTokenTypeAsTargetLabel(getCodeGenerator().g, ttype);
+ st.add("tokenName", text);
+ return st.render();
+ }
+
+ // x=(A|B)
+ public String getImplicitSetLabel(String id) {
+ ST st = getTemplates().getInstanceOf("ImplicitSetLabel");
+ st.add("id", id);
+ return st.render();
+ }
+
+ public String getImplicitRuleLabel(String ruleName) {
+ ST st = getTemplates().getInstanceOf("ImplicitRuleLabel");
+ st.add("ruleName", ruleName);
+ return st.render();
+ }
+
+ public String getElementListName(String name) {
+ ST st = getTemplates().getInstanceOf("ElementListName");
+ st.add("elemName", getElementName(name));
+ return st.render();
+ }
+
+ public String getElementName(String name) {
+ if (".".equals(name)) {
+ return "_wild";
+ }
+
+ if ( getCodeGenerator().g.getRule(name)!=null ) return name;
+ int ttype = getCodeGenerator().g.getTokenType(name);
+ if ( ttype==Token.INVALID_TYPE ) return name;
+ return getTokenTypeAsTargetLabel(getCodeGenerator().g, ttype);
+ }
+
+ /**
+ * Gets the maximum number of 16-bit unsigned integers that can be encoded
+ * in a single segment of the serialized ATN.
+ *
+ * @see SerializedATN#getSegments
+ *
+ * @return the serialized ATN segment limit
+ */
+ public int getSerializedATNSegmentLimit() {
+ return Integer.MAX_VALUE;
+ }
+
+ /** How many bits should be used to do inline token type tests? Java assumes
+ * a 64-bit word for bitsets. Must be a valid wordsize for your target like
+ * 8, 16, 32, 64, etc...
+ *
+ * @since 4.5
+ */
+ public int getInlineTestSetWordSize() { return 64; }
+
+ public boolean grammarSymbolCausesIssueInGeneratedCode(GrammarAST idNode) {
+ switch (idNode.getParent().getType()) {
+ case ANTLRParser.ASSIGN:
+ switch (idNode.getParent().getParent().getType()) {
+ case ANTLRParser.ELEMENT_OPTIONS:
+ case ANTLRParser.OPTIONS:
+ return false;
+
+ default:
+ break;
+ }
+
+ break;
+
+ case ANTLRParser.AT:
+ case ANTLRParser.ELEMENT_OPTIONS:
+ return false;
+
+ case ANTLRParser.LEXER_ACTION_CALL:
+ if (idNode.getChildIndex() == 0) {
+ // first child is the command name which is part of the ANTLR language
+ return false;
+ }
+
+ // arguments to the command should be checked
+ break;
+
+ default:
+ break;
+ }
+
+ return visibleGrammarSymbolCausesIssueInGeneratedCode(idNode);
+ }
+
+ protected abstract boolean visibleGrammarSymbolCausesIssueInGeneratedCode(GrammarAST idNode);
+
+ public boolean templatesExist() {
+ String groupFileName = CodeGenerator.TEMPLATE_ROOT + "/" + getLanguage() + "/" + getLanguage() + STGroup.GROUP_FILE_EXTENSION;
+ STGroup result = null;
+ try {
+ result = new STGroupFile(groupFileName);
+ }
+ catch (IllegalArgumentException iae) {
+ result = null;
+ }
+ return result!=null;
+ }
+
+
+ protected STGroup loadTemplates() {
+ String groupFileName = CodeGenerator.TEMPLATE_ROOT + "/" + getLanguage() + "/" + getLanguage() + STGroup.GROUP_FILE_EXTENSION;
+ STGroup result = null;
+ try {
+ result = new STGroupFile(groupFileName);
+ }
+ catch (IllegalArgumentException iae) {
+ gen.tool.errMgr.toolError(ErrorType.MISSING_CODE_GEN_TEMPLATES,
+ iae,
+ language);
+ }
+ if ( result==null ) return null;
+ result.registerRenderer(Integer.class, new NumberRenderer());
+ result.registerRenderer(String.class, new StringRenderer());
+ result.setListener(new STErrorListener() {
+ @Override
+ public void compileTimeError(STMessage msg) {
+ reportError(msg);
+ }
+
+ @Override
+ public void runTimeError(STMessage msg) {
+ reportError(msg);
+ }
+
+ @Override
+ public void IOError(STMessage msg) {
+ reportError(msg);
+ }
+
+ @Override
+ public void internalError(STMessage msg) {
+ reportError(msg);
+ }
+
+ private void reportError(STMessage msg) {
+ getCodeGenerator().tool.errMgr.toolError(ErrorType.STRING_TEMPLATE_WARNING, msg.cause, msg.toString());
+ }
+ });
+
+ return result;
+ }
+
+ /**
+ * @since 4.3
+ */
+ public boolean wantsBaseListener() {
+ return true;
+ }
+
+ /**
+ * @since 4.3
+ */
+ public boolean wantsBaseVisitor() {
+ return true;
+ }
+
+ /**
+ * @since 4.3
+ */
+ public boolean supportsOverloadedMethods() {
+ return true;
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/Wildcard.java b/tool/src/org/antlr/v4/codegen/Wildcard.java
new file mode 100644
index 0000000..5cff64e
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/Wildcard.java
@@ -0,0 +1,40 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen;
+
+import org.antlr.v4.codegen.model.MatchToken;
+import org.antlr.v4.tool.ast.GrammarAST;
+
+public class Wildcard extends MatchToken {
+ public Wildcard(OutputModelFactory factory, GrammarAST ast) {
+ super(factory, ast);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/Action.java b/tool/src/org/antlr/v4/codegen/model/Action.java
new file mode 100644
index 0000000..0b9c692
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/Action.java
@@ -0,0 +1,83 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.runtime.CommonToken;
+import org.antlr.v4.codegen.ActionTranslator;
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.codegen.model.chunk.ActionChunk;
+import org.antlr.v4.codegen.model.chunk.ActionTemplate;
+import org.antlr.v4.codegen.model.chunk.ActionText;
+import org.antlr.v4.codegen.model.decl.StructDecl;
+import org.antlr.v4.parse.ANTLRParser;
+import org.antlr.v4.tool.ast.ActionAST;
+import org.stringtemplate.v4.ST;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** */
+public class Action extends RuleElement {
+ @ModelElement public List<ActionChunk> chunks;
+
+ public Action(OutputModelFactory factory, ActionAST ast) {
+ super(factory,ast);
+ RuleFunction rf = factory.getCurrentRuleFunction();
+ if (ast != null) {
+ chunks = ActionTranslator.translateAction(factory, rf, ast.token, ast);
+ }
+ else {
+ chunks = new ArrayList<ActionChunk>();
+ }
+ //System.out.println("actions="+chunks);
+ }
+
+ public Action(OutputModelFactory factory, StructDecl ctx, String action) {
+ super(factory,null);
+ ActionAST ast = new ActionAST(new CommonToken(ANTLRParser.ACTION, action));
+ RuleFunction rf = factory.getCurrentRuleFunction();
+ if ( rf!=null ) { // we can translate
+ ast.resolver = rf.rule;
+ chunks = ActionTranslator.translateActionChunk(factory, rf, action, ast);
+ }
+ else {
+ chunks = new ArrayList<ActionChunk>();
+ chunks.add(new ActionText(ctx, action));
+ }
+ }
+
+ public Action(OutputModelFactory factory, StructDecl ctx, ST actionST) {
+ super(factory, null);
+ chunks = new ArrayList<ActionChunk>();
+ chunks.add(new ActionTemplate(ctx, actionST));
+ }
+
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/AddToLabelList.java b/tool/src/org/antlr/v4/codegen/model/AddToLabelList.java
new file mode 100644
index 0000000..066b858
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/AddToLabelList.java
@@ -0,0 +1,46 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.codegen.model.decl.Decl;
+
+/** */
+public class AddToLabelList extends SrcOp {
+ public Decl label;
+ public String listName;
+
+ public AddToLabelList(OutputModelFactory factory, String listName, Decl label) {
+ super(factory);
+ this.label = label;
+ this.listName = listName;
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/AltBlock.java b/tool/src/org/antlr/v4/codegen/model/AltBlock.java
new file mode 100644
index 0000000..b3459e9
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/AltBlock.java
@@ -0,0 +1,51 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.runtime.atn.BlockStartState;
+import org.antlr.v4.tool.ast.GrammarAST;
+
+import java.util.List;
+
+public class AltBlock extends Choice {
+// @ModelElement public ThrowNoViableAlt error;
+
+ public AltBlock(OutputModelFactory factory,
+ GrammarAST blkOrEbnfRootAST,
+ List<CodeBlockForAlt> alts)
+ {
+ super(factory, blkOrEbnfRootAST, alts);
+ decision = ((BlockStartState)blkOrEbnfRootAST.atnState).decision;
+ // interp.predict() throws exception
+// this.error = new ThrowNoViableAlt(factory, blkOrEbnfRootAST, null);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/ArgAction.java b/tool/src/org/antlr/v4/codegen/model/ArgAction.java
new file mode 100644
index 0000000..38ef4d9
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/ArgAction.java
@@ -0,0 +1,43 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.tool.ast.ActionAST;
+
+public class ArgAction extends Action {
+ /** Context type of invoked rule */
+ public String ctxType;
+ public ArgAction(OutputModelFactory factory, ActionAST ast, String ctxType) {
+ super(factory, ast);
+ this.ctxType = ctxType;
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/BaseListenerFile.java b/tool/src/org/antlr/v4/codegen/model/BaseListenerFile.java
new file mode 100644
index 0000000..505d505
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/BaseListenerFile.java
@@ -0,0 +1,38 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+
+public class BaseListenerFile extends ListenerFile {
+ public BaseListenerFile(OutputModelFactory factory, String fileName) {
+ super(factory, fileName);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/BaseVisitorFile.java b/tool/src/org/antlr/v4/codegen/model/BaseVisitorFile.java
new file mode 100644
index 0000000..62e669b
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/BaseVisitorFile.java
@@ -0,0 +1,38 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+
+public class BaseVisitorFile extends VisitorFile {
+ public BaseVisitorFile(OutputModelFactory factory, String fileName) {
+ super(factory, fileName);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/CaptureNextToken.java b/tool/src/org/antlr/v4/codegen/model/CaptureNextToken.java
new file mode 100644
index 0000000..63dd3db
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/CaptureNextToken.java
@@ -0,0 +1,41 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+
+public class CaptureNextToken extends SrcOp {
+ public String varName;
+ public CaptureNextToken(OutputModelFactory factory, String varName) {
+ super(factory);
+ this.varName = varName;
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/CaptureNextTokenType.java b/tool/src/org/antlr/v4/codegen/model/CaptureNextTokenType.java
new file mode 100644
index 0000000..ffb4cfc
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/CaptureNextTokenType.java
@@ -0,0 +1,42 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+
+/** */
+public class CaptureNextTokenType extends SrcOp {
+ public String varName;
+ public CaptureNextTokenType(OutputModelFactory factory, String varName) {
+ super(factory);
+ this.varName = varName;
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/Choice.java b/tool/src/org/antlr/v4/codegen/model/Choice.java
new file mode 100644
index 0000000..bef2c45
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/Choice.java
@@ -0,0 +1,97 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.codegen.model.decl.Decl;
+import org.antlr.v4.codegen.model.decl.TokenTypeDecl;
+import org.antlr.v4.misc.Utils;
+import org.antlr.v4.runtime.misc.IntervalSet;
+import org.antlr.v4.tool.ast.GrammarAST;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** The class hierarchy underneath SrcOp is pretty deep but makes sense that,
+ * for example LL1StarBlock is a kind of LL1Loop which is a kind of Choice.
+ * The problem is it's impossible to figure
+ * out how to construct one of these deeply nested objects because of the
+ * long super constructor call chain. Instead, I decided to in-line all of
+ * this and then look for opportunities to re-factor code into functions.
+ * It makes sense to use a class hierarchy to share data fields, but I don't
+ * think it makes sense to factor code using super constructors because
+ * it has too much work to do.
+ */
+public abstract class Choice extends RuleElement {
+ public int decision = -1;
+ public Decl label;
+
+ @ModelElement public List<CodeBlockForAlt> alts;
+ @ModelElement public List<SrcOp> preamble = new ArrayList<SrcOp>();
+
+ public Choice(OutputModelFactory factory,
+ GrammarAST blkOrEbnfRootAST,
+ List<CodeBlockForAlt> alts)
+ {
+ super(factory, blkOrEbnfRootAST);
+ this.alts = alts;
+ }
+
+ public void addPreambleOp(SrcOp op) {
+ preamble.add(op);
+ }
+
+ public List<String[]> getAltLookaheadAsStringLists(IntervalSet[] altLookSets) {
+ List<String[]> altLook = new ArrayList<String[]>();
+ for (IntervalSet s : altLookSets) {
+ altLook.add(factory.getGenerator().getTarget().getTokenTypesAsTargetLabels(factory.getGrammar(), s.toArray()));
+ }
+ return altLook;
+ }
+
+ public TestSetInline addCodeForLookaheadTempVar(IntervalSet look) {
+ List<SrcOp> testOps = factory.getLL1Test(look, ast);
+ TestSetInline expr = Utils.find(testOps, TestSetInline.class);
+ if (expr != null) {
+ Decl d = new TokenTypeDecl(factory, expr.varName);
+ factory.getCurrentRuleFunction().addLocalDecl(d);
+ CaptureNextTokenType nextType = new CaptureNextTokenType(factory,expr.varName);
+ addPreambleOp(nextType);
+ }
+ return expr;
+ }
+
+ public ThrowNoViableAlt getThrowNoViableAlt(OutputModelFactory factory,
+ GrammarAST blkAST,
+ IntervalSet expecting) {
+ return new ThrowNoViableAlt(factory, blkAST, expecting);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/CodeBlockForAlt.java b/tool/src/org/antlr/v4/codegen/model/CodeBlockForAlt.java
new file mode 100644
index 0000000..7c2c8b7
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/CodeBlockForAlt.java
@@ -0,0 +1,42 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.codegen.model.decl.CodeBlock;
+
+/** Contains Rewrite block (usually as last op) */
+public class CodeBlockForAlt extends CodeBlock {
+
+ public CodeBlockForAlt(OutputModelFactory factory) {
+ super(factory);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/CodeBlockForOuterMostAlt.java b/tool/src/org/antlr/v4/codegen/model/CodeBlockForOuterMostAlt.java
new file mode 100644
index 0000000..856d15a
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/CodeBlockForOuterMostAlt.java
@@ -0,0 +1,54 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.tool.Alternative;
+
+/** The code associated with the outermost alternative of a rule.
+ * Sometimes we might want to treat them differently in the
+ * code generation.
+ */
+public class CodeBlockForOuterMostAlt extends CodeBlockForAlt {
+ /**
+ * The label for the alternative; or null if the alternative is not labeled.
+ */
+ public String altLabel;
+ /**
+ * The alternative.
+ */
+ public Alternative alt;
+
+ public CodeBlockForOuterMostAlt(OutputModelFactory factory, Alternative alt) {
+ super(factory);
+ this.alt = alt;
+ altLabel = alt.ast.altLabel!=null ? alt.ast.altLabel.getText() : null;
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/DispatchMethod.java b/tool/src/org/antlr/v4/codegen/model/DispatchMethod.java
new file mode 100644
index 0000000..ab119f6
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/DispatchMethod.java
@@ -0,0 +1,38 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+
+public class DispatchMethod extends OutputModelObject {
+ public DispatchMethod(OutputModelFactory factory) {
+ super(factory);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/ElementFrequenciesVisitor.java b/tool/src/org/antlr/v4/codegen/model/ElementFrequenciesVisitor.java
new file mode 100644
index 0000000..2226d37
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/ElementFrequenciesVisitor.java
@@ -0,0 +1,166 @@
+package org.antlr.v4.codegen.model;
+
+import org.antlr.runtime.tree.TreeNodeStream;
+import org.antlr.v4.misc.FrequencySet;
+import org.antlr.v4.misc.MutableInt;
+import org.antlr.v4.parse.GrammarTreeVisitor;
+import org.antlr.v4.tool.ErrorManager;
+import org.antlr.v4.tool.ast.ActionAST;
+import org.antlr.v4.tool.ast.AltAST;
+import org.antlr.v4.tool.ast.GrammarAST;
+import org.antlr.v4.tool.ast.TerminalAST;
+
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.Map;
+
+public class ElementFrequenciesVisitor extends GrammarTreeVisitor {
+ final Deque<FrequencySet<String>> frequencies;
+
+ public ElementFrequenciesVisitor(TreeNodeStream input) {
+ super(input);
+ frequencies = new ArrayDeque<FrequencySet<String>>();
+ frequencies.push(new FrequencySet<String>());
+ }
+
+ /** During code gen, we can assume tree is in good shape */
+ @Override
+ public ErrorManager getErrorManager() { return super.getErrorManager(); }
+
+ /*
+ * Common
+ */
+
+ /**
+ * Generate a frequency set as the union of two input sets. If an
+ * element is contained in both sets, the value for the output will be
+ * the maximum of the two input values.
+ *
+ * @param a The first set.
+ * @param b The second set.
+ * @return The union of the two sets, with the maximum value chosen
+ * whenever both sets contain the same key.
+ */
+ protected static FrequencySet<String> combineMax(FrequencySet<String> a, FrequencySet<String> b) {
+ FrequencySet<String> result = combineAndClip(a, b, 1);
+ for (Map.Entry<String, MutableInt> entry : a.entrySet()) {
+ result.get(entry.getKey()).v = entry.getValue().v;
+ }
+
+ for (Map.Entry<String, MutableInt> entry : b.entrySet()) {
+ MutableInt slot = result.get(entry.getKey());
+ slot.v = Math.max(slot.v, entry.getValue().v);
+ }
+
+ return result;
+ }
+
+ /**
+ * Generate a frequency set as the union of two input sets, with the
+ * values clipped to a specified maximum value. If an element is
+ * contained in both sets, the value for the output, prior to clipping,
+ * will be the sum of the two input values.
+ *
+ * @param a The first set.
+ * @param b The second set.
+ * @param clip The maximum value to allow for any output.
+ * @return The sum of the two sets, with the individual elements clipped
+ * to the maximum value gived by {@code clip}.
+ */
+ protected static FrequencySet<String> combineAndClip(FrequencySet<String> a, FrequencySet<String> b, int clip) {
+ FrequencySet<String> result = new FrequencySet<String>();
+ for (Map.Entry<String, MutableInt> entry : a.entrySet()) {
+ for (int i = 0; i < entry.getValue().v; i++) {
+ result.add(entry.getKey());
+ }
+ }
+
+ for (Map.Entry<String, MutableInt> entry : b.entrySet()) {
+ for (int i = 0; i < entry.getValue().v; i++) {
+ result.add(entry.getKey());
+ }
+ }
+
+ for (Map.Entry<String, MutableInt> entry : result.entrySet()) {
+ entry.getValue().v = Math.min(entry.getValue().v, clip);
+ }
+
+ return result;
+ }
+
+ @Override
+ public void tokenRef(TerminalAST ref) {
+ frequencies.peek().add(ref.getText());
+ }
+
+ @Override
+ public void ruleRef(GrammarAST ref, ActionAST arg) {
+ frequencies.peek().add(ref.getText());
+ }
+
+ /*
+ * Parser rules
+ */
+
+ @Override
+ protected void enterAlternative(AltAST tree) {
+ frequencies.push(new FrequencySet<String>());
+ }
+
+ @Override
+ protected void exitAlternative(AltAST tree) {
+ frequencies.push(combineMax(frequencies.pop(), frequencies.pop()));
+ }
+
+ @Override
+ protected void enterElement(GrammarAST tree) {
+ frequencies.push(new FrequencySet<String>());
+ }
+
+ @Override
+ protected void exitElement(GrammarAST tree) {
+ frequencies.push(combineAndClip(frequencies.pop(), frequencies.pop(), 2));
+ }
+
+ @Override
+ protected void exitSubrule(GrammarAST tree) {
+ if (tree.getType() == CLOSURE || tree.getType() == POSITIVE_CLOSURE) {
+ for (Map.Entry<String, MutableInt> entry : frequencies.peek().entrySet()) {
+ entry.getValue().v = 2;
+ }
+ }
+ }
+
+ /*
+ * Lexer rules
+ */
+
+ @Override
+ protected void enterLexerAlternative(GrammarAST tree) {
+ frequencies.push(new FrequencySet<String>());
+ }
+
+ @Override
+ protected void exitLexerAlternative(GrammarAST tree) {
+ frequencies.push(combineMax(frequencies.pop(), frequencies.pop()));
+ }
+
+ @Override
+ protected void enterLexerElement(GrammarAST tree) {
+ frequencies.push(new FrequencySet<String>());
+ }
+
+ @Override
+ protected void exitLexerElement(GrammarAST tree) {
+ frequencies.push(combineAndClip(frequencies.pop(), frequencies.pop(), 2));
+ }
+
+ @Override
+ protected void exitLexerSubrule(GrammarAST tree) {
+ if (tree.getType() == CLOSURE || tree.getType() == POSITIVE_CLOSURE) {
+ for (Map.Entry<String, MutableInt> entry : frequencies.peek().entrySet()) {
+ entry.getValue().v = 2;
+ }
+ }
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/ExceptionClause.java b/tool/src/org/antlr/v4/codegen/model/ExceptionClause.java
new file mode 100644
index 0000000..3009a7d
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/ExceptionClause.java
@@ -0,0 +1,48 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.tool.ast.ActionAST;
+
+public class ExceptionClause extends SrcOp {
+ @ModelElement public Action catchArg;
+ @ModelElement public Action catchAction;
+
+ public ExceptionClause(OutputModelFactory factory,
+ ActionAST catchArg,
+ ActionAST catchAction)
+ {
+ super(factory, catchArg);
+ this.catchArg = new Action(factory, catchArg);
+ this.catchAction = new Action(factory, catchAction);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/InvokeRule.java b/tool/src/org/antlr/v4/codegen/model/InvokeRule.java
new file mode 100644
index 0000000..70c9f29
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/InvokeRule.java
@@ -0,0 +1,105 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.ActionTranslator;
+import org.antlr.v4.codegen.CodeGenerator;
+import org.antlr.v4.codegen.ParserFactory;
+import org.antlr.v4.codegen.model.chunk.ActionChunk;
+import org.antlr.v4.codegen.model.decl.Decl;
+import org.antlr.v4.codegen.model.decl.RuleContextDecl;
+import org.antlr.v4.codegen.model.decl.RuleContextListDecl;
+import org.antlr.v4.parse.ANTLRParser;
+import org.antlr.v4.runtime.atn.RuleTransition;
+import org.antlr.v4.runtime.misc.OrderedHashSet;
+import org.antlr.v4.tool.Rule;
+import org.antlr.v4.tool.ast.ActionAST;
+import org.antlr.v4.tool.ast.GrammarAST;
+
+import java.util.List;
+
+/** */
+public class InvokeRule extends RuleElement implements LabeledOp {
+ public String name;
+ public OrderedHashSet<Decl> labels = new OrderedHashSet<Decl>(); // TODO: should need just 1
+ public String ctxName;
+
+ @ModelElement public List<ActionChunk> argExprsChunks;
+
+ public InvokeRule(ParserFactory factory, GrammarAST ast, GrammarAST labelAST) {
+ super(factory, ast);
+ if ( ast.atnState!=null ) {
+ RuleTransition ruleTrans = (RuleTransition)ast.atnState.transition(0);
+ stateNumber = ast.atnState.stateNumber;
+ }
+
+ this.name = ast.getText();
+ CodeGenerator gen = factory.getGenerator();
+ Rule r = factory.getGrammar().getRule(name);
+ ctxName = gen.getTarget().getRuleFunctionContextStructName(r);
+
+ // TODO: move to factory
+ RuleFunction rf = factory.getCurrentRuleFunction();
+ if ( labelAST!=null ) {
+ // for x=r, define <rule-context-type> x and list_x
+ String label = labelAST.getText();
+ if ( labelAST.parent.getType() == ANTLRParser.PLUS_ASSIGN ) {
+ factory.defineImplicitLabel(ast, this);
+ String listLabel = gen.getTarget().getListLabel(label);
+ RuleContextListDecl l = new RuleContextListDecl(factory, listLabel, ctxName);
+ rf.addContextDecl(ast.getAltLabel(), l);
+ }
+ else {
+ RuleContextDecl d = new RuleContextDecl(factory,label,ctxName);
+ labels.add(d);
+ rf.addContextDecl(ast.getAltLabel(), d);
+ }
+ }
+
+ ActionAST arg = (ActionAST)ast.getFirstChildWithType(ANTLRParser.ARG_ACTION);
+ if ( arg != null ) {
+ argExprsChunks = ActionTranslator.translateAction(factory, rf, arg.token, arg);
+ }
+
+ // If action refs rule as rulename not label, we need to define implicit label
+ if ( factory.getCurrentOuterMostAlt().ruleRefsInActions.containsKey(ast.getText()) ) {
+ String label = gen.getTarget().getImplicitRuleLabel(ast.getText());
+ RuleContextDecl d = new RuleContextDecl(factory,label,ctxName);
+ labels.add(d);
+ rf.addContextDecl(ast.getAltLabel(), d);
+ }
+ }
+
+ @Override
+ public List<Decl> getLabels() {
+ return labels.elements();
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/LL1AltBlock.java b/tool/src/org/antlr/v4/codegen/model/LL1AltBlock.java
new file mode 100644
index 0000000..1bac9a4
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/LL1AltBlock.java
@@ -0,0 +1,53 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.runtime.atn.DecisionState;
+import org.antlr.v4.runtime.misc.IntervalSet;
+import org.antlr.v4.tool.ast.GrammarAST;
+
+import java.util.List;
+
+/** (A | B | C) */
+public class LL1AltBlock extends LL1Choice {
+ public LL1AltBlock(OutputModelFactory factory, GrammarAST blkAST, List<CodeBlockForAlt> alts) {
+ super(factory, blkAST, alts);
+ this.decision = ((DecisionState)blkAST.atnState).decision;
+
+ /** Lookahead for each alt 1..n */
+ IntervalSet[] altLookSets = factory.getGrammar().decisionLOOK.get(decision);
+ altLook = getAltLookaheadAsStringLists(altLookSets);
+
+ IntervalSet expecting = IntervalSet.or(altLookSets); // combine alt sets
+ this.error = getThrowNoViableAlt(factory, blkAST, expecting);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/LL1Choice.java b/tool/src/org/antlr/v4/codegen/model/LL1Choice.java
new file mode 100644
index 0000000..3153ad9
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/LL1Choice.java
@@ -0,0 +1,48 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.tool.ast.GrammarAST;
+
+import java.util.List;
+
+public abstract class LL1Choice extends Choice {
+ /** Token names for each alt 0..n-1 */
+ public List<String[]> altLook;
+ @ModelElement public ThrowNoViableAlt error;
+
+ public LL1Choice(OutputModelFactory factory, GrammarAST blkAST,
+ List<CodeBlockForAlt> alts)
+ {
+ super(factory, blkAST, alts);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/LL1Loop.java b/tool/src/org/antlr/v4/codegen/model/LL1Loop.java
new file mode 100644
index 0000000..6cd0779
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/LL1Loop.java
@@ -0,0 +1,71 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.runtime.misc.IntervalSet;
+import org.antlr.v4.tool.ast.GrammarAST;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** */
+public abstract class LL1Loop extends Choice {
+ /** The state associated wih the (A|B|...) block not loopback, which
+ * is super.stateNumber
+ */
+ public int blockStartStateNumber;
+ public int loopBackStateNumber;
+
+ @ModelElement public OutputModelObject loopExpr;
+ @ModelElement public List<SrcOp> iteration;
+
+ public LL1Loop(OutputModelFactory factory,
+ GrammarAST blkAST,
+ List<CodeBlockForAlt> alts)
+ {
+ super(factory, blkAST, alts);
+ }
+
+ public void addIterationOp(SrcOp op) {
+ if ( iteration==null ) iteration = new ArrayList<SrcOp>();
+ iteration.add(op);
+ }
+
+ public SrcOp addCodeForLoopLookaheadTempVar(IntervalSet look) {
+ TestSetInline expr = addCodeForLookaheadTempVar(look);
+ if (expr != null) {
+ CaptureNextTokenType nextType = new CaptureNextTokenType(factory, expr.varName);
+ addIterationOp(nextType);
+ }
+ return expr;
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/LL1OptionalBlock.java b/tool/src/org/antlr/v4/codegen/model/LL1OptionalBlock.java
new file mode 100644
index 0000000..74ca312
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/LL1OptionalBlock.java
@@ -0,0 +1,47 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.tool.ast.GrammarAST;
+
+import java.util.List;
+
+/** An optional block is just an alternative block where the last alternative
+ * is epsilon. The analysis takes care of adding to the empty alternative.
+ *
+ * (A | B | C)?
+ */
+public class LL1OptionalBlock extends LL1AltBlock {
+ public LL1OptionalBlock(OutputModelFactory factory, GrammarAST blkAST, List<CodeBlockForAlt> alts) {
+ super(factory, blkAST, alts);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/LL1OptionalBlockSingleAlt.java b/tool/src/org/antlr/v4/codegen/model/LL1OptionalBlockSingleAlt.java
new file mode 100644
index 0000000..eacfd5a
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/LL1OptionalBlockSingleAlt.java
@@ -0,0 +1,65 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.runtime.atn.DecisionState;
+import org.antlr.v4.runtime.misc.IntervalSet;
+import org.antlr.v4.tool.ast.GrammarAST;
+
+import java.util.List;
+
+/** (A B C)? */
+public class LL1OptionalBlockSingleAlt extends LL1Choice {
+ @ModelElement public SrcOp expr;
+ @ModelElement public List<SrcOp> followExpr; // might not work in template if size>1
+
+ public LL1OptionalBlockSingleAlt(OutputModelFactory factory,
+ GrammarAST blkAST,
+ List<CodeBlockForAlt> alts)
+ {
+ super(factory, blkAST, alts);
+ this.decision = ((DecisionState)blkAST.atnState).decision;
+
+ /** Lookahead for each alt 1..n */
+// IntervalSet[] altLookSets = LinearApproximator.getLL1LookaheadSets(dfa);
+ IntervalSet[] altLookSets = factory.getGrammar().decisionLOOK.get(decision);
+ altLook = getAltLookaheadAsStringLists(altLookSets);
+ IntervalSet look = altLookSets[0];
+ IntervalSet followLook = altLookSets[1];
+
+ IntervalSet expecting = look.or(followLook);
+ this.error = getThrowNoViableAlt(factory, blkAST, expecting);
+
+ expr = addCodeForLookaheadTempVar(look);
+ followExpr = factory.getLL1Test(followLook, blkAST);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/LL1PlusBlockSingleAlt.java b/tool/src/org/antlr/v4/codegen/model/LL1PlusBlockSingleAlt.java
new file mode 100644
index 0000000..a7076ce
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/LL1PlusBlockSingleAlt.java
@@ -0,0 +1,58 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.runtime.atn.PlusBlockStartState;
+import org.antlr.v4.runtime.misc.IntervalSet;
+import org.antlr.v4.tool.ast.BlockAST;
+import org.antlr.v4.tool.ast.GrammarAST;
+
+import java.util.List;
+
+/** */
+public class LL1PlusBlockSingleAlt extends LL1Loop {
+ public LL1PlusBlockSingleAlt(OutputModelFactory factory, GrammarAST plusRoot, List<CodeBlockForAlt> alts) {
+ super(factory, plusRoot, alts);
+
+ BlockAST blkAST = (BlockAST)plusRoot.getChild(0);
+ PlusBlockStartState blkStart = (PlusBlockStartState)blkAST.atnState;
+
+ stateNumber = blkStart.loopBackState.stateNumber;
+ blockStartStateNumber = blkStart.stateNumber;
+ PlusBlockStartState plus = (PlusBlockStartState)blkAST.atnState;
+ this.decision = plus.loopBackState.decision;
+ IntervalSet[] altLookSets = factory.getGrammar().decisionLOOK.get(decision);
+
+ IntervalSet loopBackLook = altLookSets[0];
+ loopExpr = addCodeForLoopLookaheadTempVar(loopBackLook);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/LL1StarBlockSingleAlt.java b/tool/src/org/antlr/v4/codegen/model/LL1StarBlockSingleAlt.java
new file mode 100644
index 0000000..4c1bf94
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/LL1StarBlockSingleAlt.java
@@ -0,0 +1,54 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.runtime.atn.StarLoopEntryState;
+import org.antlr.v4.runtime.misc.IntervalSet;
+import org.antlr.v4.tool.ast.GrammarAST;
+
+import java.util.List;
+
+/** */
+public class LL1StarBlockSingleAlt extends LL1Loop {
+ public LL1StarBlockSingleAlt(OutputModelFactory factory, GrammarAST starRoot, List<CodeBlockForAlt> alts) {
+ super(factory, starRoot, alts);
+
+ StarLoopEntryState star = (StarLoopEntryState)starRoot.atnState;
+ loopBackStateNumber = star.loopBackState.stateNumber;
+ this.decision = star.decision;
+ IntervalSet[] altLookSets = factory.getGrammar().decisionLOOK.get(decision);
+ assert altLookSets.length == 2;
+ IntervalSet enterLook = altLookSets[0];
+ IntervalSet exitLook = altLookSets[1];
+ loopExpr = addCodeForLoopLookaheadTempVar(enterLook);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/LabeledOp.java b/tool/src/org/antlr/v4/codegen/model/LabeledOp.java
new file mode 100644
index 0000000..26ad2d3
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/LabeledOp.java
@@ -0,0 +1,40 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.model.decl.Decl;
+
+import java.util.List;
+
+/** All the rule elements we can label like tokens, rules, sets, wildcard. */
+public interface LabeledOp {
+ public List<Decl> getLabels();
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/LeftRecursiveRuleFunction.java b/tool/src/org/antlr/v4/codegen/model/LeftRecursiveRuleFunction.java
new file mode 100644
index 0000000..adbc3a6
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/LeftRecursiveRuleFunction.java
@@ -0,0 +1,76 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.CodeGenerator;
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.codegen.model.decl.RuleContextDecl;
+import org.antlr.v4.codegen.model.decl.RuleContextListDecl;
+import org.antlr.v4.codegen.model.decl.StructDecl;
+import org.antlr.v4.parse.ANTLRParser;
+import org.antlr.v4.runtime.misc.Pair;
+import org.antlr.v4.tool.LeftRecursiveRule;
+import org.antlr.v4.tool.Rule;
+import org.antlr.v4.tool.ast.GrammarAST;
+
+public class LeftRecursiveRuleFunction extends RuleFunction {
+ public LeftRecursiveRuleFunction(OutputModelFactory factory, LeftRecursiveRule r) {
+ super(factory, r);
+
+ CodeGenerator gen = factory.getGenerator();
+ // Since we delete x=lr, we have to manually add decls for all labels
+ // on left-recur refs to proper structs
+ for (Pair<GrammarAST,String> pair : r.leftRecursiveRuleRefLabels) {
+ GrammarAST idAST = pair.a;
+ String altLabel = pair.b;
+ String label = idAST.getText();
+ GrammarAST rrefAST = (GrammarAST)idAST.getParent().getChild(1);
+ if ( rrefAST.getType() == ANTLRParser.RULE_REF ) {
+ Rule targetRule = factory.getGrammar().getRule(rrefAST.getText());
+ String ctxName = gen.getTarget().getRuleFunctionContextStructName(targetRule);
+ RuleContextDecl d;
+ if (idAST.getParent().getType() == ANTLRParser.ASSIGN) {
+ d = new RuleContextDecl(factory, label, ctxName);
+ }
+ else {
+ d = new RuleContextListDecl(factory, label, ctxName);
+ }
+
+ StructDecl struct = ruleCtx;
+ if ( altLabelCtxs!=null ) {
+ StructDecl s = altLabelCtxs.get(altLabel);
+ if ( s!=null ) struct = s; // if alt label, use subctx
+ }
+ struct.addDecl(d); // stick in overall rule's ctx
+ }
+ }
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/Lexer.java b/tool/src/org/antlr/v4/codegen/model/Lexer.java
new file mode 100644
index 0000000..ef44e4c
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/Lexer.java
@@ -0,0 +1,58 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.tool.Grammar;
+import org.antlr.v4.tool.LexerGrammar;
+import org.antlr.v4.tool.Rule;
+
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+public class Lexer extends Recognizer {
+ public Map<String,Integer> channels;
+ public LexerFile file;
+ public Collection<String> modes;
+
+ @ModelElement public LinkedHashMap<Rule, RuleActionFunction> actionFuncs =
+ new LinkedHashMap<Rule, RuleActionFunction>();
+
+ public Lexer(OutputModelFactory factory, LexerFile file) {
+ super(factory);
+ this.file = file; // who contains us?
+
+ Grammar g = factory.getGrammar();
+ channels = new LinkedHashMap<String, Integer>(g.channelNameToValueMap);
+ modes = ((LexerGrammar)g).modes.keySet();
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/LexerFile.java b/tool/src/org/antlr/v4/codegen/model/LexerFile.java
new file mode 100644
index 0000000..8bec073
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/LexerFile.java
@@ -0,0 +1,55 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.tool.Grammar;
+import org.antlr.v4.tool.ast.ActionAST;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class LexerFile extends OutputFile {
+ public String genPackage; // from -package cmd-line
+ @ModelElement public Lexer lexer;
+ @ModelElement public Map<String, Action> namedActions;
+
+ public LexerFile(OutputModelFactory factory, String fileName) {
+ super(factory, fileName);
+ namedActions = new HashMap<String, Action>();
+ Grammar g = factory.getGrammar();
+ for (String name : g.namedActions.keySet()) {
+ ActionAST ast = g.namedActions.get(name);
+ namedActions.put(name, new Action(factory, ast));
+ }
+ genPackage = factory.getGrammar().tool.genPackage;
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/ListenerDispatchMethod.java b/tool/src/org/antlr/v4/codegen/model/ListenerDispatchMethod.java
new file mode 100644
index 0000000..9332d13
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/ListenerDispatchMethod.java
@@ -0,0 +1,41 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+
+public class ListenerDispatchMethod extends DispatchMethod {
+ public boolean isEnter;
+
+ public ListenerDispatchMethod(OutputModelFactory factory, boolean isEnter) {
+ super(factory);
+ this.isEnter = isEnter;
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/ListenerFile.java b/tool/src/org/antlr/v4/codegen/model/ListenerFile.java
new file mode 100644
index 0000000..99f6ebf
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/ListenerFile.java
@@ -0,0 +1,87 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.runtime.misc.Pair;
+import org.antlr.v4.tool.Grammar;
+import org.antlr.v4.tool.Rule;
+import org.antlr.v4.tool.ast.ActionAST;
+import org.antlr.v4.tool.ast.AltAST;
+
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/** A model object representing a parse tree listener file.
+ * These are the rules specific events triggered by a parse tree visitor.
+ */
+public class ListenerFile extends OutputFile {
+ public String genPackage; // from -package cmd-line
+ public String grammarName;
+ public String parserName;
+ /**
+ * The names of all listener contexts.
+ */
+ public Set<String> listenerNames = new LinkedHashSet<String>();
+ /**
+ * For listener contexts created for a labeled outer alternative, maps from
+ * a listener context name to the name of the rule which defines the
+ * context.
+ */
+ public Map<String, String> listenerLabelRuleNames = new LinkedHashMap<String, String>();
+
+ @ModelElement public Action header;
+
+ public ListenerFile(OutputModelFactory factory, String fileName) {
+ super(factory, fileName);
+ Grammar g = factory.getGrammar();
+ parserName = g.getRecognizerName();
+ grammarName = g.name;
+ for (Rule r : g.rules.values()) {
+ Map<String, List<Pair<Integer,AltAST>>> labels = r.getAltLabels();
+ if ( labels!=null ) {
+ for (Map.Entry<String, List<Pair<Integer, AltAST>>> pair : labels.entrySet()) {
+ listenerNames.add(pair.getKey());
+ listenerLabelRuleNames.put(pair.getKey(), r.name);
+ }
+ }
+ else {
+ // only add rule context if no labels
+ listenerNames.add(r.name);
+ }
+ }
+ ActionAST ast = g.namedActions.get("header");
+ if ( ast!=null ) header = new Action(factory, ast);
+ genPackage = factory.getGrammar().tool.genPackage;
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/Loop.java b/tool/src/org/antlr/v4/codegen/model/Loop.java
new file mode 100644
index 0000000..50fbd6f
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/Loop.java
@@ -0,0 +1,60 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.tool.ast.GrammarAST;
+import org.antlr.v4.tool.ast.QuantifierAST;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Loop extends Choice {
+ public int blockStartStateNumber;
+ public int loopBackStateNumber;
+ public final int exitAlt;
+
+ @ModelElement public List<SrcOp> iteration;
+
+ public Loop(OutputModelFactory factory,
+ GrammarAST blkOrEbnfRootAST,
+ List<CodeBlockForAlt> alts)
+ {
+ super(factory, blkOrEbnfRootAST, alts);
+ boolean nongreedy = (blkOrEbnfRootAST instanceof QuantifierAST) && !((QuantifierAST)blkOrEbnfRootAST).isGreedy();
+ exitAlt = nongreedy ? 1 : alts.size() + 1;
+ }
+
+ public void addIterationOp(SrcOp op) {
+ if ( iteration==null ) iteration = new ArrayList<SrcOp>();
+ iteration.add(op);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/MatchNotSet.java b/tool/src/org/antlr/v4/codegen/model/MatchNotSet.java
new file mode 100644
index 0000000..8df741c
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/MatchNotSet.java
@@ -0,0 +1,41 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.tool.ast.GrammarAST;
+
+public class MatchNotSet extends MatchSet {
+ public String varName = "_la";
+ public MatchNotSet(OutputModelFactory factory, GrammarAST ast) {
+ super(factory, ast);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/MatchSet.java b/tool/src/org/antlr/v4/codegen/model/MatchSet.java
new file mode 100644
index 0000000..e6d02a1
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/MatchSet.java
@@ -0,0 +1,52 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.codegen.model.decl.Decl;
+import org.antlr.v4.codegen.model.decl.TokenTypeDecl;
+import org.antlr.v4.runtime.atn.SetTransition;
+import org.antlr.v4.tool.ast.GrammarAST;
+
+public class MatchSet extends MatchToken {
+ @ModelElement public TestSetInline expr;
+ @ModelElement public CaptureNextTokenType capture;
+
+ public MatchSet(OutputModelFactory factory, GrammarAST ast) {
+ super(factory, ast);
+ SetTransition st = (SetTransition)ast.atnState.transition(0);
+ int wordSize = factory.getGenerator().getTarget().getInlineTestSetWordSize();
+ expr = new TestSetInline(factory, null, st.set, wordSize);
+ Decl d = new TokenTypeDecl(factory, expr.varName);
+ factory.getCurrentRuleFunction().addLocalDecl(d);
+ capture = new CaptureNextTokenType(factory,expr.varName);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/MatchToken.java b/tool/src/org/antlr/v4/codegen/model/MatchToken.java
new file mode 100644
index 0000000..8405e78
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/MatchToken.java
@@ -0,0 +1,63 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.CodeGenerator;
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.codegen.model.decl.Decl;
+import org.antlr.v4.tool.Grammar;
+import org.antlr.v4.tool.ast.GrammarAST;
+import org.antlr.v4.tool.ast.TerminalAST;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** */
+public class MatchToken extends RuleElement implements LabeledOp {
+ public String name;
+ public int ttype;
+ public List<Decl> labels = new ArrayList<Decl>();
+
+ public MatchToken(OutputModelFactory factory, TerminalAST ast) {
+ super(factory, ast);
+ Grammar g = factory.getGrammar();
+ CodeGenerator gen = factory.getGenerator();
+ ttype = g.getTokenType(ast.getText());
+ name = gen.getTarget().getTokenTypeAsTargetLabel(g, ttype);
+ }
+
+ public MatchToken(OutputModelFactory factory, GrammarAST ast) {
+ super(factory, ast);
+ }
+
+ @Override
+ public List<Decl> getLabels() { return labels; }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/ModelElement.java b/tool/src/org/antlr/v4/codegen/model/ModelElement.java
new file mode 100644
index 0000000..0dc38c2
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/ModelElement.java
@@ -0,0 +1,41 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/** Indicate field of OutputModelObject is an element to be walked by
+ * OutputModelWalker.
+ */
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ModelElement {
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/OptionalBlock.java b/tool/src/org/antlr/v4/codegen/model/OptionalBlock.java
new file mode 100644
index 0000000..c1f2cb3
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/OptionalBlock.java
@@ -0,0 +1,46 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.tool.ast.GrammarAST;
+
+import java.util.List;
+
+/** */
+public class OptionalBlock extends AltBlock {
+ public OptionalBlock(OutputModelFactory factory,
+ GrammarAST questionAST,
+ List<CodeBlockForAlt> alts)
+ {
+ super(factory, questionAST, alts);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/OutputFile.java b/tool/src/org/antlr/v4/codegen/model/OutputFile.java
new file mode 100644
index 0000000..16b2384
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/OutputFile.java
@@ -0,0 +1,53 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.Tool;
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.tool.Grammar;
+
+public abstract class OutputFile extends OutputModelObject {
+ public final String fileName;
+ public final String grammarFileName;
+ public final String ANTLRVersion;
+ public final String TokenLabelType;
+ public final String InputSymbolType;
+
+ public OutputFile(OutputModelFactory factory, String fileName) {
+ super(factory);
+ this.fileName = fileName;
+ Grammar g = factory.getGrammar();
+ grammarFileName = g.fileName;
+ ANTLRVersion = Tool.VERSION;
+ TokenLabelType = g.getOptionString("TokenLabelType");
+ InputSymbolType = TokenLabelType;
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/OutputModelObject.java b/tool/src/org/antlr/v4/codegen/model/OutputModelObject.java
new file mode 100644
index 0000000..6f793be
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/OutputModelObject.java
@@ -0,0 +1,49 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.tool.ast.GrammarAST;
+
+/** */
+public abstract class OutputModelObject {
+ public OutputModelFactory factory;
+ public GrammarAST ast;
+
+ public OutputModelObject() {}
+
+ public OutputModelObject(OutputModelFactory factory) { this(factory, null); }
+
+ public OutputModelObject(OutputModelFactory factory, GrammarAST ast) {
+ this.factory = factory;
+ this.ast = ast;
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/Parser.java b/tool/src/org/antlr/v4/codegen/model/Parser.java
new file mode 100644
index 0000000..770d904
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/Parser.java
@@ -0,0 +1,47 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Parser extends Recognizer {
+ public ParserFile file;
+
+ @ModelElement public List<RuleFunction> funcs = new ArrayList<RuleFunction>();
+
+ public Parser(OutputModelFactory factory, ParserFile file) {
+ super(factory);
+ this.file = file; // who contains us?
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/ParserFile.java b/tool/src/org/antlr/v4/codegen/model/ParserFile.java
new file mode 100644
index 0000000..28ef200
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/ParserFile.java
@@ -0,0 +1,63 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.tool.Grammar;
+import org.antlr.v4.tool.ast.ActionAST;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/** */
+public class ParserFile extends OutputFile {
+ public String genPackage; // from -package cmd-line
+ @ModelElement public Parser parser;
+ @ModelElement public Map<String, Action> namedActions;
+ public Boolean genListener = false;
+ public Boolean genVisitor = false;
+ public String grammarName;
+
+ public ParserFile(OutputModelFactory factory, String fileName) {
+ super(factory, fileName);
+ Grammar g = factory.getGrammar();
+ namedActions = new HashMap<String, Action>();
+ for (String name : g.namedActions.keySet()) {
+ ActionAST ast = g.namedActions.get(name);
+ namedActions.put(name, new Action(factory, ast));
+ }
+ genPackage = g.tool.genPackage;
+ // need the below members in the ST for Python
+ genListener = g.tool.gen_listener;
+ genVisitor = g.tool.gen_visitor;
+ grammarName = g.name;
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/PlusBlock.java b/tool/src/org/antlr/v4/codegen/model/PlusBlock.java
new file mode 100644
index 0000000..a200d30
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/PlusBlock.java
@@ -0,0 +1,58 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.runtime.atn.PlusBlockStartState;
+import org.antlr.v4.runtime.atn.PlusLoopbackState;
+import org.antlr.v4.tool.ast.BlockAST;
+import org.antlr.v4.tool.ast.GrammarAST;
+
+import java.util.List;
+
+public class PlusBlock extends Loop {
+ @ModelElement public ThrowNoViableAlt error;
+
+ public PlusBlock(OutputModelFactory factory,
+ GrammarAST plusRoot,
+ List<CodeBlockForAlt> alts)
+ {
+ super(factory, plusRoot, alts);
+ BlockAST blkAST = (BlockAST)plusRoot.getChild(0);
+ PlusBlockStartState blkStart = (PlusBlockStartState)blkAST.atnState;
+ PlusLoopbackState loop = blkStart.loopBackState;
+ stateNumber = blkStart.loopBackState.stateNumber;
+ blockStartStateNumber = blkStart.stateNumber;
+ loopBackStateNumber = loop.stateNumber;
+ this.error = getThrowNoViableAlt(factory, plusRoot, null);
+ decision = loop.decision;
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/Recognizer.java b/tool/src/org/antlr/v4/codegen/model/Recognizer.java
new file mode 100644
index 0000000..7e3f95b
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/Recognizer.java
@@ -0,0 +1,135 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2014 Terence Parr
+ * Copyright (c) 2014 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.CodeGenerator;
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.codegen.model.chunk.ActionChunk;
+import org.antlr.v4.codegen.model.chunk.ActionText;
+import org.antlr.v4.tool.Grammar;
+import org.antlr.v4.tool.Rule;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+
+public abstract class Recognizer extends OutputModelObject {
+ public String name;
+ public String grammarName;
+ public String grammarFileName;
+ public Map<String,Integer> tokens;
+
+ /**
+ * @deprecated This field is provided only for compatibility with code
+ * generation targets which have not yet been updated to use
+ * {@link #literalNames} and {@link #symbolicNames}.
+ */
+ @Deprecated
+ public String[] tokenNames;
+
+ public String[] literalNames;
+ public String[] symbolicNames;
+ public Set<String> ruleNames;
+ public Collection<Rule> rules;
+ @ModelElement public ActionChunk superClass;
+
+ @ModelElement public SerializedATN atn;
+ @ModelElement public LinkedHashMap<Rule, RuleSempredFunction> sempredFuncs =
+ new LinkedHashMap<Rule, RuleSempredFunction>();
+
+ public Recognizer(OutputModelFactory factory) {
+ super(factory);
+
+ Grammar g = factory.getGrammar();
+ grammarFileName = new File(g.fileName).getName();
+ grammarName = g.name;
+ name = g.getRecognizerName();
+ tokens = new LinkedHashMap<String,Integer>();
+ for (Map.Entry<String, Integer> entry : g.tokenNameToTypeMap.entrySet()) {
+ Integer ttype = entry.getValue();
+ if ( ttype>0 ) {
+ tokens.put(entry.getKey(), ttype);
+ }
+ }
+
+ ruleNames = g.rules.keySet();
+ rules = g.rules.values();
+ atn = new SerializedATN(factory, g.atn);
+ if (g.getOptionString("superClass") != null) {
+ superClass = new ActionText(null, g.getOptionString("superClass"));
+ }
+ else {
+ superClass = null;
+ }
+
+ CodeGenerator gen = factory.getGenerator();
+ tokenNames = translateTokenStringsToTarget(g.getTokenDisplayNames(), gen);
+ literalNames = translateTokenStringsToTarget(g.getTokenLiteralNames(), gen);
+ symbolicNames = translateTokenStringsToTarget(g.getTokenSymbolicNames(), gen);
+ }
+
+ protected static String[] translateTokenStringsToTarget(String[] tokenStrings, CodeGenerator gen) {
+ String[] result = tokenStrings.clone();
+ for (int i = 0; i < tokenStrings.length; i++) {
+ result[i] = translateTokenStringToTarget(tokenStrings[i], gen);
+ }
+
+ int lastTrueEntry = result.length - 1;
+ while (lastTrueEntry >= 0 && result[lastTrueEntry] == null) {
+ lastTrueEntry --;
+ }
+
+ if (lastTrueEntry < result.length - 1) {
+ result = Arrays.copyOf(result, lastTrueEntry + 1);
+ }
+
+ return result;
+ }
+
+ protected static String translateTokenStringToTarget(String tokenName, CodeGenerator gen) {
+ if (tokenName == null) {
+ return null;
+ }
+
+ if (tokenName.charAt(0) == '\'') {
+ boolean addQuotes = false;
+ String targetString =
+ gen.getTarget().getTargetStringLiteralFromANTLRStringLiteral(gen, tokenName, addQuotes);
+ return "\"'" + targetString + "'\"";
+ }
+ else {
+ return gen.getTarget().getTargetStringLiteralFromString(tokenName, true);
+ }
+ }
+
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/RuleActionFunction.java b/tool/src/org/antlr/v4/codegen/model/RuleActionFunction.java
new file mode 100644
index 0000000..8e65462
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/RuleActionFunction.java
@@ -0,0 +1,53 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.tool.Rule;
+
+import java.util.LinkedHashMap;
+
+public class RuleActionFunction extends OutputModelObject {
+ public String name;
+ public String ctxType;
+ public int ruleIndex;
+
+ /** Map actionIndex to Action */
+ @ModelElement public LinkedHashMap<Integer, Action> actions =
+ new LinkedHashMap<Integer, Action>();
+
+ public RuleActionFunction(OutputModelFactory factory, Rule r, String ctxType) {
+ super(factory);
+ name = r.name;
+ ruleIndex = r.index;
+ this.ctxType = ctxType;
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/RuleElement.java b/tool/src/org/antlr/v4/codegen/model/RuleElement.java
new file mode 100644
index 0000000..c2b2f52
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/RuleElement.java
@@ -0,0 +1,45 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.tool.ast.GrammarAST;
+
+public class RuleElement extends SrcOp {
+ /** Associated ATN state for this rule elements (action, token, ruleref, ...) */
+ public int stateNumber;
+
+ public RuleElement(OutputModelFactory factory, GrammarAST ast) {
+ super(factory, ast);
+ if ( ast != null && ast.atnState!=null ) stateNumber = ast.atnState.stateNumber;
+ }
+
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/RuleFunction.java b/tool/src/org/antlr/v4/codegen/model/RuleFunction.java
new file mode 100644
index 0000000..25d6d0f
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/RuleFunction.java
@@ -0,0 +1,290 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.runtime.RecognitionException;
+import org.antlr.runtime.tree.CommonTreeNodeStream;
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.codegen.model.decl.AltLabelStructDecl;
+import org.antlr.v4.codegen.model.decl.AttributeDecl;
+import org.antlr.v4.codegen.model.decl.ContextRuleGetterDecl;
+import org.antlr.v4.codegen.model.decl.ContextRuleListGetterDecl;
+import org.antlr.v4.codegen.model.decl.ContextRuleListIndexedGetterDecl;
+import org.antlr.v4.codegen.model.decl.ContextTokenGetterDecl;
+import org.antlr.v4.codegen.model.decl.ContextTokenListGetterDecl;
+import org.antlr.v4.codegen.model.decl.ContextTokenListIndexedGetterDecl;
+import org.antlr.v4.codegen.model.decl.Decl;
+import org.antlr.v4.codegen.model.decl.StructDecl;
+import org.antlr.v4.misc.FrequencySet;
+import org.antlr.v4.misc.Utils;
+import org.antlr.v4.parse.GrammarASTAdaptor;
+import org.antlr.v4.runtime.atn.ATNState;
+import org.antlr.v4.runtime.misc.IntervalSet;
+import org.antlr.v4.runtime.misc.OrderedHashSet;
+import org.antlr.v4.runtime.misc.Pair;
+import org.antlr.v4.tool.Attribute;
+import org.antlr.v4.tool.ErrorType;
+import org.antlr.v4.tool.Rule;
+import org.antlr.v4.tool.ast.ActionAST;
+import org.antlr.v4.tool.ast.AltAST;
+import org.antlr.v4.tool.ast.GrammarAST;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.antlr.v4.parse.ANTLRParser.RULE_REF;
+import static org.antlr.v4.parse.ANTLRParser.TOKEN_REF;
+
+/** */
+public class RuleFunction extends OutputModelObject {
+ public String name;
+ public List<String> modifiers;
+ public String ctxType;
+ public Collection<String> ruleLabels;
+ public Collection<String> tokenLabels;
+ public ATNState startState;
+ public int index;
+ public Rule rule;
+ public AltLabelStructDecl[] altToContext;
+ public boolean hasLookaheadBlock;
+
+ @ModelElement public List<SrcOp> code;
+ @ModelElement public OrderedHashSet<Decl> locals; // TODO: move into ctx?
+ @ModelElement public Collection<AttributeDecl> args = null;
+ @ModelElement public StructDecl ruleCtx;
+ @ModelElement public Map<String,AltLabelStructDecl> altLabelCtxs;
+ @ModelElement public Map<String,Action> namedActions;
+ @ModelElement public Action finallyAction;
+ @ModelElement public List<ExceptionClause> exceptions;
+ @ModelElement public List<SrcOp> postamble;
+
+ public RuleFunction(OutputModelFactory factory, Rule r) {
+ super(factory);
+ this.name = r.name;
+ this.rule = r;
+ if ( r.modifiers!=null && !r.modifiers.isEmpty() ) {
+ this.modifiers = new ArrayList<String>();
+ for (GrammarAST t : r.modifiers) modifiers.add(t.getText());
+ }
+ modifiers = Utils.nodesToStrings(r.modifiers);
+
+ index = r.index;
+
+ ruleCtx = new StructDecl(factory, r);
+ altToContext = new AltLabelStructDecl[r.getOriginalNumberOfAlts()+1];
+ addContextGetters(factory, r);
+
+ if ( r.args!=null ) {
+ Collection<Attribute> decls = r.args.attributes.values();
+ if ( decls.size()>0 ) {
+ args = new ArrayList<AttributeDecl>();
+ ruleCtx.addDecls(decls);
+ for (Attribute a : decls) {
+ args.add(new AttributeDecl(factory, a));
+ }
+ ruleCtx.ctorAttrs = args;
+ }
+ }
+ if ( r.retvals!=null ) {
+ ruleCtx.addDecls(r.retvals.attributes.values());
+ }
+ if ( r.locals!=null ) {
+ ruleCtx.addDecls(r.locals.attributes.values());
+ }
+
+ ruleLabels = r.getElementLabelNames();
+ tokenLabels = r.getTokenRefs();
+ if ( r.exceptions!=null ) {
+ exceptions = new ArrayList<ExceptionClause>();
+ for (GrammarAST e : r.exceptions) {
+ ActionAST catchArg = (ActionAST)e.getChild(0);
+ ActionAST catchAction = (ActionAST)e.getChild(1);
+ exceptions.add(new ExceptionClause(factory, catchArg, catchAction));
+ }
+ }
+
+ startState = factory.getGrammar().atn.ruleToStartState[r.index];
+ }
+
+ public void addContextGetters(OutputModelFactory factory, Rule r) {
+ // Add ctx labels for elements in alts with no -> label
+ List<AltAST> altsNoLabels = r.getUnlabeledAltASTs();
+ if ( altsNoLabels!=null ) {
+ Set<Decl> decls = getDeclsForAllElements(altsNoLabels);
+ // we know to put in rule ctx, so do it directly
+ for (Decl d : decls) ruleCtx.addDecl(d);
+ }
+
+ // make structs for -> labeled alts, define ctx labels for elements
+ altLabelCtxs = new HashMap<String,AltLabelStructDecl>();
+ Map<String, List<Pair<Integer, AltAST>>> labels = r.getAltLabels();
+ if ( labels!=null ) {
+ for (Map.Entry<String, List<Pair<Integer, AltAST>>> entry : labels.entrySet()) {
+ String label = entry.getKey();
+ List<AltAST> alts = new ArrayList<AltAST>();
+ for (Pair<Integer, AltAST> pair : entry.getValue()) {
+ alts.add(pair.b);
+ }
+
+ Set<Decl> decls = getDeclsForAllElements(alts);
+ for (Pair<Integer, AltAST> pair : entry.getValue()) {
+ Integer altNum = pair.a;
+ altToContext[altNum] = new AltLabelStructDecl(factory, r, altNum, label);
+ if (!altLabelCtxs.containsKey(label)) {
+ altLabelCtxs.put(label, altToContext[altNum]);
+ }
+
+ // we know which ctx to put in, so do it directly
+ for (Decl d : decls) {
+ altToContext[altNum].addDecl(d);
+ }
+ }
+ }
+ }
+ }
+
+ public void fillNamedActions(OutputModelFactory factory, Rule r) {
+ if ( r.finallyAction!=null ) {
+ finallyAction = new Action(factory, r.finallyAction);
+ }
+
+ namedActions = new HashMap<String, Action>();
+ for (String name : r.namedActions.keySet()) {
+ ActionAST ast = r.namedActions.get(name);
+ namedActions.put(name, new Action(factory, ast));
+ }
+ }
+
+ /** for all alts, find which ref X or r needs List
+ Must see across alts. If any alt needs X or r as list, then
+ define as list.
+ */
+ public Set<Decl> getDeclsForAllElements(List<AltAST> altASTs) {
+ Set<String> needsList = new HashSet<String>();
+ List<GrammarAST> allRefs = new ArrayList<GrammarAST>();
+ for (AltAST ast : altASTs) {
+ IntervalSet reftypes = new IntervalSet(RULE_REF, TOKEN_REF);
+ List<GrammarAST> refs = ast.getNodesWithType(reftypes);
+ allRefs.addAll(refs);
+ FrequencySet<String> altFreq = getElementFrequenciesForAlt(ast);
+ for (GrammarAST t : refs) {
+ String refLabelName = t.getText();
+ if ( altFreq.count(refLabelName)>1 ) {
+ needsList.add(refLabelName);
+ }
+ }
+ }
+ Set<Decl> decls = new LinkedHashSet<Decl>();
+ for (GrammarAST t : allRefs) {
+ String refLabelName = t.getText();
+ List<Decl> d = getDeclForAltElement(t,
+ refLabelName,
+ needsList.contains(refLabelName));
+ decls.addAll(d);
+ }
+ return decls;
+ }
+
+ /** Given list of X and r refs in alt, compute how many of each there are */
+ protected FrequencySet<String> getElementFrequenciesForAlt(AltAST ast) {
+ try {
+ ElementFrequenciesVisitor visitor = new ElementFrequenciesVisitor(new CommonTreeNodeStream(new GrammarASTAdaptor(), ast));
+ visitor.outerAlternative();
+ if (visitor.frequencies.size() != 1) {
+ factory.getGrammar().tool.errMgr.toolError(ErrorType.INTERNAL_ERROR);
+ return new FrequencySet<String>();
+ }
+
+ return visitor.frequencies.peek();
+ }
+ catch (RecognitionException ex) {
+ factory.getGrammar().tool.errMgr.toolError(ErrorType.INTERNAL_ERROR, ex);
+ return new FrequencySet<String>();
+ }
+ }
+
+ public List<Decl> getDeclForAltElement(GrammarAST t, String refLabelName, boolean needList) {
+ List<Decl> decls = new ArrayList<Decl>();
+ if ( t.getType()==RULE_REF ) {
+ Rule rref = factory.getGrammar().getRule(t.getText());
+ String ctxName = factory.getGenerator().getTarget()
+ .getRuleFunctionContextStructName(rref);
+ if ( needList) {
+ if(factory.getGenerator().getTarget().supportsOverloadedMethods())
+ decls.add( new ContextRuleListGetterDecl(factory, refLabelName, ctxName) );
+ decls.add( new ContextRuleListIndexedGetterDecl(factory, refLabelName, ctxName) );
+ }
+ else {
+ decls.add( new ContextRuleGetterDecl(factory, refLabelName, ctxName) );
+ }
+ }
+ else {
+ if ( needList ) {
+ if(factory.getGenerator().getTarget().supportsOverloadedMethods())
+ decls.add( new ContextTokenListGetterDecl(factory, refLabelName) );
+ decls.add( new ContextTokenListIndexedGetterDecl(factory, refLabelName) );
+ }
+ else {
+ decls.add( new ContextTokenGetterDecl(factory, refLabelName) );
+ }
+ }
+ return decls;
+ }
+
+ /** Add local var decl */
+ public void addLocalDecl(Decl d) {
+ if ( locals ==null ) locals = new OrderedHashSet<Decl>();
+ locals.add(d);
+ d.isLocal = true;
+ }
+
+ /** Add decl to struct ctx for rule or alt if labeled */
+ public void addContextDecl(String altLabel, Decl d) {
+ CodeBlockForOuterMostAlt alt = d.getOuterMostAltCodeBlock();
+ // if we found code blk and might be alt label, try to add to that label ctx
+ if ( alt!=null && altLabelCtxs!=null ) {
+// System.out.println(d.name+" lives in alt "+alt.alt.altNum);
+ AltLabelStructDecl altCtx = altLabelCtxs.get(altLabel);
+ if ( altCtx!=null ) { // we have an alt ctx
+// System.out.println("ctx is "+ altCtx.name);
+ altCtx.addDecl(d);
+ return;
+ }
+ }
+ ruleCtx.addDecl(d); // stick in overall rule's ctx
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/RuleSempredFunction.java b/tool/src/org/antlr/v4/codegen/model/RuleSempredFunction.java
new file mode 100644
index 0000000..2b1f6a1
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/RuleSempredFunction.java
@@ -0,0 +1,40 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.tool.Rule;
+
+public class RuleSempredFunction extends RuleActionFunction {
+ public RuleSempredFunction(OutputModelFactory factory, Rule r, String ctxType) {
+ super(factory, r, ctxType);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/SemPred.java b/tool/src/org/antlr/v4/codegen/model/SemPred.java
new file mode 100644
index 0000000..605091f
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/SemPred.java
@@ -0,0 +1,97 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.ActionTranslator;
+import org.antlr.v4.codegen.CodeGenerator;
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.codegen.model.chunk.ActionChunk;
+import org.antlr.v4.runtime.atn.AbstractPredicateTransition;
+import org.antlr.v4.tool.ast.ActionAST;
+import org.antlr.v4.tool.ast.GrammarAST;
+
+import java.util.List;
+
+/** */
+public class SemPred extends Action {
+ /**
+ * The user-specified terminal option {@code fail}, if it was used and the
+ * value is a string literal. For example:
+ *
+ * <p>
+ * {@code {pred}?<fail='message'>}</p>
+ */
+ public String msg;
+ /**
+ * The predicate string with <code>{</code> and <code>}?</code> stripped from the ends.
+ */
+ public String predicate;
+
+ /**
+ * The translated chunks of the user-specified terminal option {@code fail},
+ * if it was used and the value is an action. For example:
+ *
+ * <p>
+ * {@code {pred}?<fail={"Java literal"}>}</p>
+ */
+ @ModelElement public List<ActionChunk> failChunks;
+
+ public SemPred(OutputModelFactory factory, ActionAST ast) {
+ super(factory,ast);
+
+ assert ast.atnState != null
+ && ast.atnState.getNumberOfTransitions() == 1
+ && ast.atnState.transition(0) instanceof AbstractPredicateTransition;
+
+ GrammarAST failNode = ast.getOptionAST("fail");
+ CodeGenerator gen = factory.getGenerator();
+ predicate = ast.getText();
+ if (predicate.startsWith("{") && predicate.endsWith("}?")) {
+ predicate = predicate.substring(1, predicate.length() - 2);
+ }
+ predicate = gen.getTarget().getTargetStringLiteralFromString(predicate);
+
+ if ( failNode==null ) return;
+
+ if ( failNode instanceof ActionAST ) {
+ ActionAST failActionNode = (ActionAST)failNode;
+ RuleFunction rf = factory.getCurrentRuleFunction();
+ failChunks = ActionTranslator.translateAction(factory, rf,
+ failActionNode.token,
+ failActionNode);
+ }
+ else {
+ msg = gen.getTarget().getTargetStringLiteralFromANTLRStringLiteral(gen,
+ failNode.getText(),
+ true);
+ }
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/SerializedATN.java b/tool/src/org/antlr/v4/codegen/model/SerializedATN.java
new file mode 100644
index 0000000..ae64c43
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/SerializedATN.java
@@ -0,0 +1,65 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.runtime.atn.ATN;
+import org.antlr.v4.runtime.atn.ATNSerializer;
+import org.antlr.v4.runtime.misc.IntegerList;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class SerializedATN extends OutputModelObject {
+ // TODO: make this into a kind of decl or multiple?
+ public List<String> serialized;
+ public SerializedATN(OutputModelFactory factory, ATN atn) {
+ super(factory);
+ IntegerList data = ATNSerializer.getSerialized(atn);
+ serialized = new ArrayList<String>(data.size());
+ for (int c : data.toArray()) {
+ String encoded = factory.getGenerator().getTarget().encodeIntAsCharEscape(c == -1 ? Character.MAX_VALUE : c);
+ serialized.add(encoded);
+ }
+// System.out.println(ATNSerializer.getDecoded(factory.getGrammar(), atn));
+ }
+
+ public String[][] getSegments() {
+ List<String[]> segments = new ArrayList<String[]>();
+ int segmentLimit = factory.getGenerator().getTarget().getSerializedATNSegmentLimit();
+ for (int i = 0; i < serialized.size(); i += segmentLimit) {
+ List<String> currentSegment = serialized.subList(i, Math.min(i + segmentLimit, serialized.size()));
+ segments.add(currentSegment.toArray(new String[currentSegment.size()]));
+ }
+
+ return segments.toArray(new String[segments.size()][]);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/SrcOp.java b/tool/src/org/antlr/v4/codegen/model/SrcOp.java
new file mode 100644
index 0000000..d4a9834
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/SrcOp.java
@@ -0,0 +1,82 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.codegen.model.decl.CodeBlock;
+import org.antlr.v4.tool.ast.GrammarAST;
+
+/** */
+public abstract class SrcOp extends OutputModelObject {
+ /** Used to create unique var names etc... */
+ public int uniqueID; // TODO: do we need?
+
+ /** All operations know in which block they live:
+ *
+ * CodeBlock, CodeBlockForAlt
+ *
+ * Templates might need to know block nesting level or find
+ * a specific declaration, etc...
+ */
+ public CodeBlock enclosingBlock;
+
+ public RuleFunction enclosingRuleRunction;
+
+ public SrcOp(OutputModelFactory factory) { this(factory,null); }
+ public SrcOp(OutputModelFactory factory, GrammarAST ast) {
+ super(factory,ast);
+ if ( ast!=null ) uniqueID = ast.token.getTokenIndex();
+ enclosingBlock = factory.getCurrentBlock();
+ enclosingRuleRunction = factory.getCurrentRuleFunction();
+ }
+
+ /** Walk upwards in model tree, looking for outer alt's code block */
+ public CodeBlockForOuterMostAlt getOuterMostAltCodeBlock() {
+ if ( this instanceof CodeBlockForOuterMostAlt ) {
+ return (CodeBlockForOuterMostAlt)this;
+ }
+ CodeBlock p = enclosingBlock;
+ while ( p!=null ) {
+ if ( p instanceof CodeBlockForOuterMostAlt ) {
+ return (CodeBlockForOuterMostAlt)p;
+ }
+ p = p.enclosingBlock;
+ }
+ return null;
+ }
+
+ /** Return label alt or return name of rule */
+ public String getContextName() {
+ CodeBlockForOuterMostAlt alt = getOuterMostAltCodeBlock();
+ if ( alt!=null && alt.altLabel!=null ) return alt.altLabel;
+ return enclosingRuleRunction.name;
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/StarBlock.java b/tool/src/org/antlr/v4/codegen/model/StarBlock.java
new file mode 100644
index 0000000..e61ef72
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/StarBlock.java
@@ -0,0 +1,52 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.runtime.atn.StarLoopEntryState;
+import org.antlr.v4.tool.ast.GrammarAST;
+
+import java.util.List;
+
+public class StarBlock extends Loop {
+ public String loopLabel;
+
+ public StarBlock(OutputModelFactory factory,
+ GrammarAST blkOrEbnfRootAST,
+ List<CodeBlockForAlt> alts)
+ {
+ super(factory, blkOrEbnfRootAST, alts);
+ loopLabel = factory.getGenerator().getTarget().getLoopLabel(blkOrEbnfRootAST);
+ StarLoopEntryState star = (StarLoopEntryState)blkOrEbnfRootAST.atnState;
+ loopBackStateNumber = star.loopBackState.stateNumber;
+ decision = star.decision;
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/Sync.java b/tool/src/org/antlr/v4/codegen/model/Sync.java
new file mode 100644
index 0000000..b9c20fc
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/Sync.java
@@ -0,0 +1,52 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.runtime.misc.IntervalSet;
+import org.antlr.v4.tool.ast.GrammarAST;
+
+/** */
+public class Sync extends SrcOp {
+ public int decision;
+// public BitSetDecl expecting;
+ public Sync(OutputModelFactory factory,
+ GrammarAST blkOrEbnfRootAST,
+ IntervalSet expecting,
+ int decision,
+ String position)
+ {
+ super(factory, blkOrEbnfRootAST);
+ this.decision = decision;
+// this.expecting = factory.createExpectingBitSet(ast, decision, expecting, position);
+// factory.defineBitSet(this.expecting);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/TestSetInline.java b/tool/src/org/antlr/v4/codegen/model/TestSetInline.java
new file mode 100644
index 0000000..0b3956c
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/TestSetInline.java
@@ -0,0 +1,84 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.runtime.misc.IntervalSet;
+import org.antlr.v4.tool.ast.GrammarAST;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** */
+public class TestSetInline extends SrcOp {
+ public int bitsetWordSize;
+ public String varName;
+ public Bitset[] bitsets;
+
+ public TestSetInline(OutputModelFactory factory, GrammarAST ast, IntervalSet set, int wordSize) {
+ super(factory, ast);
+ bitsetWordSize = wordSize;
+ Bitset[] withZeroOffset = createBitsets(factory, set, wordSize, true);
+ Bitset[] withoutZeroOffset = createBitsets(factory, set, wordSize, false);
+ this.bitsets = withZeroOffset.length <= withoutZeroOffset.length ? withZeroOffset : withoutZeroOffset;
+ this.varName = "_la";
+ }
+
+ private static Bitset[] createBitsets(OutputModelFactory factory,
+ IntervalSet set,
+ int wordSize,
+ boolean useZeroOffset) {
+ List<Bitset> bitsetList = new ArrayList<Bitset>();
+ for (int ttype : set.toArray()) {
+ Bitset current = !bitsetList.isEmpty() ? bitsetList.get(bitsetList.size() - 1) : null;
+ if (current == null || ttype > (current.shift + wordSize-1)) {
+ current = new Bitset();
+ if (useZeroOffset && ttype >= 0 && ttype < wordSize-1) {
+ current.shift = 0;
+ }
+ else {
+ current.shift = ttype;
+ }
+
+ bitsetList.add(current);
+ }
+
+ current.ttypes.add(factory.getGenerator().getTarget().getTokenTypeAsTargetLabel(factory.getGrammar(), ttype));
+ }
+
+ return bitsetList.toArray(new Bitset[bitsetList.size()]);
+ }
+
+ public static final class Bitset {
+ public int shift;
+ public final List<String> ttypes = new ArrayList<String>();
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/ThrowEarlyExitException.java b/tool/src/org/antlr/v4/codegen/model/ThrowEarlyExitException.java
new file mode 100644
index 0000000..17f8574
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/ThrowEarlyExitException.java
@@ -0,0 +1,42 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.runtime.misc.IntervalSet;
+import org.antlr.v4.tool.ast.GrammarAST;
+
+/** */
+public class ThrowEarlyExitException extends ThrowRecognitionException {
+ public ThrowEarlyExitException(OutputModelFactory factory, GrammarAST ast, IntervalSet expecting) {
+ super(factory, ast, expecting);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/ThrowNoViableAlt.java b/tool/src/org/antlr/v4/codegen/model/ThrowNoViableAlt.java
new file mode 100644
index 0000000..eb07be7
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/ThrowNoViableAlt.java
@@ -0,0 +1,44 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.runtime.misc.IntervalSet;
+import org.antlr.v4.tool.ast.GrammarAST;
+
+/** */
+public class ThrowNoViableAlt extends ThrowRecognitionException {
+ public ThrowNoViableAlt(OutputModelFactory factory, GrammarAST blkOrEbnfRootAST,
+ IntervalSet expecting)
+ {
+ super(factory, blkOrEbnfRootAST, expecting);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/ThrowRecognitionException.java b/tool/src/org/antlr/v4/codegen/model/ThrowRecognitionException.java
new file mode 100644
index 0000000..8815764
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/ThrowRecognitionException.java
@@ -0,0 +1,53 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.runtime.misc.IntervalSet;
+import org.antlr.v4.tool.ast.GrammarAST;
+
+/** */
+public class ThrowRecognitionException extends SrcOp {
+ public int decision;
+ public String grammarFile;
+ public int grammarLine;
+ public int grammarCharPosInLine;
+
+ public ThrowRecognitionException(OutputModelFactory factory, GrammarAST ast, IntervalSet expecting) {
+ super(factory, ast);
+ //this.decision = ((BlockStartState)ast.ATNState).decision;
+ grammarLine = ast.getLine();
+ grammarLine = ast.getCharPositionInLine();
+ grammarFile = factory.getGrammar().fileName;
+ //this.expecting = factory.createExpectingBitSet(ast, decision, expecting, "error");
+// factory.defineBitSet(this.expecting);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/VisitorDispatchMethod.java b/tool/src/org/antlr/v4/codegen/model/VisitorDispatchMethod.java
new file mode 100644
index 0000000..a56dc6e
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/VisitorDispatchMethod.java
@@ -0,0 +1,38 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+
+public class VisitorDispatchMethod extends DispatchMethod {
+ public VisitorDispatchMethod(OutputModelFactory factory) {
+ super(factory);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/VisitorFile.java b/tool/src/org/antlr/v4/codegen/model/VisitorFile.java
new file mode 100644
index 0000000..e1370a9
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/VisitorFile.java
@@ -0,0 +1,84 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.v4.codegen.model;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.runtime.misc.Pair;
+import org.antlr.v4.tool.Grammar;
+import org.antlr.v4.tool.Rule;
+import org.antlr.v4.tool.ast.ActionAST;
+import org.antlr.v4.tool.ast.AltAST;
+
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class VisitorFile extends OutputFile {
+ public String genPackage; // from -package cmd-line
+ public String grammarName;
+ public String parserName;
+ /**
+ * The names of all rule contexts which may need to be visited.
+ */
+ public Set<String> visitorNames = new LinkedHashSet<String>();
+ /**
+ * For rule contexts created for a labeled outer alternative, maps from
+ * a listener context name to the name of the rule which defines the
+ * context.
+ */
+ public Map<String, String> visitorLabelRuleNames = new LinkedHashMap<String, String>();
+
+ @ModelElement public Action header;
+
+ public VisitorFile(OutputModelFactory factory, String fileName) {
+ super(factory, fileName);
+ Grammar g = factory.getGrammar();
+ parserName = g.getRecognizerName();
+ grammarName = g.name;
+ for (Rule r : g.rules.values()) {
+ Map<String, List<Pair<Integer, AltAST>>> labels = r.getAltLabels();
+ if ( labels!=null ) {
+ for (Map.Entry<String, List<Pair<Integer, AltAST>>> pair : labels.entrySet()) {
+ visitorNames.add(pair.getKey());
+ visitorLabelRuleNames.put(pair.getKey(), r.name);
+ }
+ }
+ else {
+ // if labels, must label all. no need for generic rule visitor then
+ visitorNames.add(r.name);
+ }
+ }
+ ActionAST ast = g.namedActions.get("header");
+ if ( ast!=null ) header = new Action(factory, ast);
+ genPackage = factory.getGrammar().tool.genPackage;
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/chunk/ActionChunk.java b/tool/src/org/antlr/v4/codegen/model/chunk/ActionChunk.java
new file mode 100644
index 0000000..3c7e364
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/chunk/ActionChunk.java
@@ -0,0 +1,44 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.chunk;
+
+import org.antlr.v4.codegen.model.OutputModelObject;
+import org.antlr.v4.codegen.model.decl.StructDecl;
+
+/** */
+public class ActionChunk extends OutputModelObject {
+ /** Where is the ctx that defines attrs,labels etc... for this action? */
+ public StructDecl ctx;
+
+ public ActionChunk(StructDecl ctx) {
+ this.ctx = ctx;
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/chunk/ActionTemplate.java b/tool/src/org/antlr/v4/codegen/model/chunk/ActionTemplate.java
new file mode 100644
index 0000000..2c2edc1
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/chunk/ActionTemplate.java
@@ -0,0 +1,43 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.chunk;
+
+import org.antlr.v4.codegen.model.decl.StructDecl;
+import org.stringtemplate.v4.ST;
+
+public class ActionTemplate extends ActionChunk {
+ public ST st;
+
+ public ActionTemplate(StructDecl ctx, ST st) {
+ super(ctx);
+ this.st = st;
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/chunk/ActionText.java b/tool/src/org/antlr/v4/codegen/model/chunk/ActionText.java
new file mode 100644
index 0000000..de3acff
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/chunk/ActionText.java
@@ -0,0 +1,43 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.chunk;
+
+import org.antlr.v4.codegen.model.decl.StructDecl;
+
+/** */
+public class ActionText extends ActionChunk {
+ public String text;
+
+ public ActionText(StructDecl ctx, String text) {
+ super(ctx);
+ this.text = text;
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/chunk/ArgRef.java b/tool/src/org/antlr/v4/codegen/model/chunk/ArgRef.java
new file mode 100644
index 0000000..2d39271
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/chunk/ArgRef.java
@@ -0,0 +1,40 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.chunk;
+
+import org.antlr.v4.codegen.model.decl.StructDecl;
+
+/** */
+public class ArgRef extends LocalRef {
+ public ArgRef(StructDecl ctx, String name) {
+ super(ctx, name);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/chunk/LabelRef.java b/tool/src/org/antlr/v4/codegen/model/chunk/LabelRef.java
new file mode 100644
index 0000000..eae4a65
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/chunk/LabelRef.java
@@ -0,0 +1,42 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.chunk;
+
+import org.antlr.v4.codegen.model.decl.StructDecl;
+
+public class LabelRef extends ActionChunk {
+ public String name;
+
+ public LabelRef(StructDecl ctx, String name) {
+ super(ctx);
+ this.name = name;
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/chunk/ListLabelRef.java b/tool/src/org/antlr/v4/codegen/model/chunk/ListLabelRef.java
new file mode 100644
index 0000000..c7af76a
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/chunk/ListLabelRef.java
@@ -0,0 +1,37 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.chunk;
+
+import org.antlr.v4.codegen.model.decl.StructDecl;
+
+public class ListLabelRef extends LabelRef {
+ public ListLabelRef(StructDecl ctx, String name) { super(ctx, name); }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/chunk/LocalRef.java b/tool/src/org/antlr/v4/codegen/model/chunk/LocalRef.java
new file mode 100644
index 0000000..3463dc8
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/chunk/LocalRef.java
@@ -0,0 +1,42 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.chunk;
+
+import org.antlr.v4.codegen.model.decl.StructDecl;
+
+public class LocalRef extends ActionChunk {
+ public String name;
+
+ public LocalRef(StructDecl ctx, String name) {
+ super(ctx);
+ this.name = name;
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/chunk/NonLocalAttrRef.java b/tool/src/org/antlr/v4/codegen/model/chunk/NonLocalAttrRef.java
new file mode 100644
index 0000000..d9a28f7
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/chunk/NonLocalAttrRef.java
@@ -0,0 +1,47 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.chunk;
+
+import org.antlr.v4.codegen.model.decl.StructDecl;
+
+public class NonLocalAttrRef extends ActionChunk {
+ public String ruleName;
+ public String name;
+ public int ruleIndex;
+
+ public NonLocalAttrRef(StructDecl ctx, String ruleName, String name, int ruleIndex) {
+ super(ctx);
+ this.name = name;
+ this.ruleName = ruleName;
+ this.ruleIndex = ruleIndex;
+ }
+
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/chunk/QRetValueRef.java b/tool/src/org/antlr/v4/codegen/model/chunk/QRetValueRef.java
new file mode 100644
index 0000000..d799e78
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/chunk/QRetValueRef.java
@@ -0,0 +1,42 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.chunk;
+
+import org.antlr.v4.codegen.model.decl.StructDecl;
+
+/** */
+public class QRetValueRef extends RetValueRef {
+ public String dict;
+ public QRetValueRef(StructDecl ctx, String dict, String name) {
+ super(ctx,name);
+ this.dict = dict;
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/chunk/RetValueRef.java b/tool/src/org/antlr/v4/codegen/model/chunk/RetValueRef.java
new file mode 100644
index 0000000..59e45fe
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/chunk/RetValueRef.java
@@ -0,0 +1,44 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.chunk;
+
+import org.antlr.v4.codegen.model.decl.StructDecl;
+
+/** */
+public class RetValueRef extends ActionChunk {
+ public String name;
+
+ public RetValueRef(StructDecl ctx, String name) {
+ super(ctx);
+ this.name = name;
+ }
+
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/chunk/RulePropertyRef.java b/tool/src/org/antlr/v4/codegen/model/chunk/RulePropertyRef.java
new file mode 100644
index 0000000..ae14863
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/chunk/RulePropertyRef.java
@@ -0,0 +1,43 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.chunk;
+
+import org.antlr.v4.codegen.model.decl.StructDecl;
+
+/** */
+public class RulePropertyRef extends ActionChunk {
+ public String label;
+
+ public RulePropertyRef(StructDecl ctx, String label) {
+ super(ctx);
+ this.label = label;
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/chunk/RulePropertyRef_ctx.java b/tool/src/org/antlr/v4/codegen/model/chunk/RulePropertyRef_ctx.java
new file mode 100644
index 0000000..aebded7
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/chunk/RulePropertyRef_ctx.java
@@ -0,0 +1,39 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.chunk;
+
+import org.antlr.v4.codegen.model.decl.StructDecl;
+
+public class RulePropertyRef_ctx extends RulePropertyRef {
+ public RulePropertyRef_ctx(StructDecl ctx, String label) {
+ super(ctx, label);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/chunk/RulePropertyRef_parser.java b/tool/src/org/antlr/v4/codegen/model/chunk/RulePropertyRef_parser.java
new file mode 100644
index 0000000..a427810
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/chunk/RulePropertyRef_parser.java
@@ -0,0 +1,40 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.chunk;
+
+import org.antlr.v4.codegen.model.decl.StructDecl;
+
+/** */
+public class RulePropertyRef_parser extends RulePropertyRef {
+ public RulePropertyRef_parser(StructDecl ctx, String label) {
+ super(ctx, label);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/chunk/RulePropertyRef_start.java b/tool/src/org/antlr/v4/codegen/model/chunk/RulePropertyRef_start.java
new file mode 100644
index 0000000..826c5d0
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/chunk/RulePropertyRef_start.java
@@ -0,0 +1,40 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.chunk;
+
+import org.antlr.v4.codegen.model.decl.StructDecl;
+
+/** */
+public class RulePropertyRef_start extends RulePropertyRef {
+ public RulePropertyRef_start(StructDecl ctx, String label) {
+ super(ctx, label);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/chunk/RulePropertyRef_stop.java b/tool/src/org/antlr/v4/codegen/model/chunk/RulePropertyRef_stop.java
new file mode 100644
index 0000000..7b9e3f2
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/chunk/RulePropertyRef_stop.java
@@ -0,0 +1,40 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.chunk;
+
+import org.antlr.v4.codegen.model.decl.StructDecl;
+
+/** */
+public class RulePropertyRef_stop extends RulePropertyRef {
+ public RulePropertyRef_stop(StructDecl ctx, String label) {
+ super(ctx, label);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/chunk/RulePropertyRef_text.java b/tool/src/org/antlr/v4/codegen/model/chunk/RulePropertyRef_text.java
new file mode 100644
index 0000000..1230105
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/chunk/RulePropertyRef_text.java
@@ -0,0 +1,40 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.chunk;
+
+import org.antlr.v4.codegen.model.decl.StructDecl;
+
+/** */
+public class RulePropertyRef_text extends RulePropertyRef {
+ public RulePropertyRef_text(StructDecl ctx, String label) {
+ super(ctx, label);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/chunk/SetAttr.java b/tool/src/org/antlr/v4/codegen/model/chunk/SetAttr.java
new file mode 100644
index 0000000..1b6e15b
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/chunk/SetAttr.java
@@ -0,0 +1,48 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.chunk;
+
+import org.antlr.v4.codegen.model.ModelElement;
+import org.antlr.v4.codegen.model.decl.StructDecl;
+
+import java.util.List;
+
+/** */
+public class SetAttr extends ActionChunk {
+ public String name;
+ @ModelElement public List<ActionChunk> rhsChunks;
+
+ public SetAttr(StructDecl ctx, String name, List<ActionChunk> rhsChunks) {
+ super(ctx);
+ this.name = name;
+ this.rhsChunks = rhsChunks;
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/chunk/SetNonLocalAttr.java b/tool/src/org/antlr/v4/codegen/model/chunk/SetNonLocalAttr.java
new file mode 100644
index 0000000..9872b6e
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/chunk/SetNonLocalAttr.java
@@ -0,0 +1,49 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.chunk;
+
+import org.antlr.v4.codegen.model.decl.StructDecl;
+
+import java.util.List;
+
+public class SetNonLocalAttr extends SetAttr {
+ public String ruleName;
+ public int ruleIndex;
+
+ public SetNonLocalAttr(StructDecl ctx,
+ String ruleName, String name, int ruleIndex,
+ List<ActionChunk> rhsChunks)
+ {
+ super(ctx, name, rhsChunks);
+ this.ruleName = ruleName;
+ this.ruleIndex = ruleIndex;
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/chunk/ThisRulePropertyRef_ctx.java b/tool/src/org/antlr/v4/codegen/model/chunk/ThisRulePropertyRef_ctx.java
new file mode 100644
index 0000000..e8dc913
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/chunk/ThisRulePropertyRef_ctx.java
@@ -0,0 +1,39 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.chunk;
+
+import org.antlr.v4.codegen.model.decl.StructDecl;
+
+public class ThisRulePropertyRef_ctx extends RulePropertyRef {
+ public ThisRulePropertyRef_ctx(StructDecl ctx, String label) {
+ super(ctx, label);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/chunk/ThisRulePropertyRef_parser.java b/tool/src/org/antlr/v4/codegen/model/chunk/ThisRulePropertyRef_parser.java
new file mode 100644
index 0000000..7cbf5d6
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/chunk/ThisRulePropertyRef_parser.java
@@ -0,0 +1,40 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.chunk;
+
+import org.antlr.v4.codegen.model.decl.StructDecl;
+
+/** */
+public class ThisRulePropertyRef_parser extends RulePropertyRef {
+ public ThisRulePropertyRef_parser(StructDecl ctx, String label) {
+ super(ctx, label);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/chunk/ThisRulePropertyRef_start.java b/tool/src/org/antlr/v4/codegen/model/chunk/ThisRulePropertyRef_start.java
new file mode 100644
index 0000000..614c973
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/chunk/ThisRulePropertyRef_start.java
@@ -0,0 +1,40 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.chunk;
+
+import org.antlr.v4.codegen.model.decl.StructDecl;
+
+/** */
+public class ThisRulePropertyRef_start extends RulePropertyRef {
+ public ThisRulePropertyRef_start(StructDecl ctx, String label) {
+ super(ctx, label);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/chunk/ThisRulePropertyRef_stop.java b/tool/src/org/antlr/v4/codegen/model/chunk/ThisRulePropertyRef_stop.java
new file mode 100644
index 0000000..65b5322
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/chunk/ThisRulePropertyRef_stop.java
@@ -0,0 +1,40 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.chunk;
+
+import org.antlr.v4.codegen.model.decl.StructDecl;
+
+/** */
+public class ThisRulePropertyRef_stop extends RulePropertyRef {
+ public ThisRulePropertyRef_stop(StructDecl ctx, String label) {
+ super(ctx, label);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/chunk/ThisRulePropertyRef_text.java b/tool/src/org/antlr/v4/codegen/model/chunk/ThisRulePropertyRef_text.java
new file mode 100644
index 0000000..7ee4d8e
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/chunk/ThisRulePropertyRef_text.java
@@ -0,0 +1,40 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.chunk;
+
+import org.antlr.v4.codegen.model.decl.StructDecl;
+
+/** */
+public class ThisRulePropertyRef_text extends RulePropertyRef {
+ public ThisRulePropertyRef_text(StructDecl ctx, String label) {
+ super(ctx, label);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/chunk/TokenPropertyRef.java b/tool/src/org/antlr/v4/codegen/model/chunk/TokenPropertyRef.java
new file mode 100644
index 0000000..8a3f7d5
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/chunk/TokenPropertyRef.java
@@ -0,0 +1,43 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.chunk;
+
+import org.antlr.v4.codegen.model.decl.StructDecl;
+
+/** */
+public class TokenPropertyRef extends ActionChunk {
+ public String label;
+
+ public TokenPropertyRef(StructDecl ctx, String label) {
+ super(ctx);
+ this.label = label;
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/chunk/TokenPropertyRef_channel.java b/tool/src/org/antlr/v4/codegen/model/chunk/TokenPropertyRef_channel.java
new file mode 100644
index 0000000..9c93690
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/chunk/TokenPropertyRef_channel.java
@@ -0,0 +1,40 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.chunk;
+
+import org.antlr.v4.codegen.model.decl.StructDecl;
+
+/** */
+public class TokenPropertyRef_channel extends TokenPropertyRef {
+ public TokenPropertyRef_channel(StructDecl ctx, String label) {
+ super(ctx, label);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/chunk/TokenPropertyRef_index.java b/tool/src/org/antlr/v4/codegen/model/chunk/TokenPropertyRef_index.java
new file mode 100644
index 0000000..a456876
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/chunk/TokenPropertyRef_index.java
@@ -0,0 +1,40 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.chunk;
+
+import org.antlr.v4.codegen.model.decl.StructDecl;
+
+/** */
+public class TokenPropertyRef_index extends TokenPropertyRef {
+ public TokenPropertyRef_index(StructDecl ctx, String label) {
+ super(ctx, label);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/chunk/TokenPropertyRef_int.java b/tool/src/org/antlr/v4/codegen/model/chunk/TokenPropertyRef_int.java
new file mode 100644
index 0000000..91c13bd
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/chunk/TokenPropertyRef_int.java
@@ -0,0 +1,40 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.chunk;
+
+import org.antlr.v4.codegen.model.decl.StructDecl;
+
+/** */
+public class TokenPropertyRef_int extends TokenPropertyRef {
+ public TokenPropertyRef_int(StructDecl ctx, String label) {
+ super(ctx, label);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/chunk/TokenPropertyRef_line.java b/tool/src/org/antlr/v4/codegen/model/chunk/TokenPropertyRef_line.java
new file mode 100644
index 0000000..f9c08f4
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/chunk/TokenPropertyRef_line.java
@@ -0,0 +1,40 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.chunk;
+
+import org.antlr.v4.codegen.model.decl.StructDecl;
+
+/** */
+public class TokenPropertyRef_line extends TokenPropertyRef {
+ public TokenPropertyRef_line(StructDecl ctx, String label) {
+ super(ctx, label);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/chunk/TokenPropertyRef_pos.java b/tool/src/org/antlr/v4/codegen/model/chunk/TokenPropertyRef_pos.java
new file mode 100644
index 0000000..469b228
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/chunk/TokenPropertyRef_pos.java
@@ -0,0 +1,40 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.chunk;
+
+import org.antlr.v4.codegen.model.decl.StructDecl;
+
+/** */
+public class TokenPropertyRef_pos extends TokenPropertyRef {
+ public TokenPropertyRef_pos(StructDecl ctx, String label) {
+ super(ctx, label);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/chunk/TokenPropertyRef_text.java b/tool/src/org/antlr/v4/codegen/model/chunk/TokenPropertyRef_text.java
new file mode 100644
index 0000000..3da4f53
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/chunk/TokenPropertyRef_text.java
@@ -0,0 +1,40 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.chunk;
+
+import org.antlr.v4.codegen.model.decl.StructDecl;
+
+/** */
+public class TokenPropertyRef_text extends TokenPropertyRef {
+ public TokenPropertyRef_text(StructDecl ctx, String label) {
+ super(ctx, label);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/chunk/TokenPropertyRef_type.java b/tool/src/org/antlr/v4/codegen/model/chunk/TokenPropertyRef_type.java
new file mode 100644
index 0000000..d495e19
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/chunk/TokenPropertyRef_type.java
@@ -0,0 +1,40 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.chunk;
+
+import org.antlr.v4.codegen.model.decl.StructDecl;
+
+/** */
+public class TokenPropertyRef_type extends TokenPropertyRef {
+ public TokenPropertyRef_type(StructDecl ctx, String label) {
+ super(ctx, label);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/chunk/TokenRef.java b/tool/src/org/antlr/v4/codegen/model/chunk/TokenRef.java
new file mode 100644
index 0000000..ac2569b
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/chunk/TokenRef.java
@@ -0,0 +1,43 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.chunk;
+
+import org.antlr.v4.codegen.model.decl.StructDecl;
+
+/** */
+public class TokenRef extends ActionChunk {
+ public String name;
+
+ public TokenRef(StructDecl ctx, String name) {
+ super(ctx);
+ this.name = name;
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/dbg.java b/tool/src/org/antlr/v4/codegen/model/dbg.java
new file mode 100644
index 0000000..4eb8386
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/dbg.java
@@ -0,0 +1,35 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model;
+
+/** */
+public class dbg extends OutputModelObject {
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/decl/AltLabelStructDecl.java b/tool/src/org/antlr/v4/codegen/model/decl/AltLabelStructDecl.java
new file mode 100644
index 0000000..5d49625
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/decl/AltLabelStructDecl.java
@@ -0,0 +1,78 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.decl;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.codegen.model.DispatchMethod;
+import org.antlr.v4.codegen.model.ListenerDispatchMethod;
+import org.antlr.v4.codegen.model.VisitorDispatchMethod;
+import org.antlr.v4.tool.Rule;
+
+import java.util.ArrayList;
+
+/** A StructDecl to handle a -> label on alt */
+public class AltLabelStructDecl extends StructDecl {
+ public int altNum;
+ public AltLabelStructDecl(OutputModelFactory factory, Rule r,
+ int altNum, String label)
+ {
+ super(factory, r);
+ this.altNum = altNum;
+ this.name = // override name set in super to the label ctx
+ factory.getGenerator().getTarget().getAltLabelContextStructName(label);
+ derivedFromName = label;
+ }
+
+ @Override
+ public void addDispatchMethods(Rule r) {
+ dispatchMethods = new ArrayList<DispatchMethod>();
+ if ( factory.getGrammar().tool.gen_listener ) {
+ dispatchMethods.add(new ListenerDispatchMethod(factory, true));
+ dispatchMethods.add(new ListenerDispatchMethod(factory, false));
+ }
+ if ( factory.getGrammar().tool.gen_visitor ) {
+ dispatchMethods.add(new VisitorDispatchMethod(factory));
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return name.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if ( obj == this ) return true;
+ if (!(obj instanceof AltLabelStructDecl)) return false;
+
+ return name.equals(((AltLabelStructDecl)obj).name);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/decl/AttributeDecl.java b/tool/src/org/antlr/v4/codegen/model/decl/AttributeDecl.java
new file mode 100644
index 0000000..7b77ecd
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/decl/AttributeDecl.java
@@ -0,0 +1,45 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.decl;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.tool.Attribute;
+
+/** */
+public class AttributeDecl extends Decl {
+ public String type;
+ public String initValue;
+ public AttributeDecl(OutputModelFactory factory, Attribute a) {
+ super(factory, a.name, a.decl);
+ this.type = a.type;
+ this.initValue = a.initValue;
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/decl/CodeBlock.java b/tool/src/org/antlr/v4/codegen/model/decl/CodeBlock.java
new file mode 100644
index 0000000..8a0890e
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/decl/CodeBlock.java
@@ -0,0 +1,85 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.decl;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.codegen.model.ModelElement;
+import org.antlr.v4.codegen.model.SrcOp;
+import org.antlr.v4.runtime.misc.OrderedHashSet;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class CodeBlock extends SrcOp {
+ public int codeBlockLevel;
+ public int treeLevel;
+
+ @ModelElement public OrderedHashSet<Decl> locals;
+ @ModelElement public List<SrcOp> preamble;
+ @ModelElement public List<SrcOp> ops;
+
+ public CodeBlock(OutputModelFactory factory) {
+ super(factory);
+ }
+
+ public CodeBlock(OutputModelFactory factory, int treeLevel, int codeBlockLevel) {
+ super(factory);
+ this.treeLevel = treeLevel;
+ this.codeBlockLevel = codeBlockLevel;
+ }
+
+ /** Add local var decl */
+ public void addLocalDecl(Decl d) {
+ if ( locals==null ) locals = new OrderedHashSet<Decl>();
+ locals.add(d);
+ d.isLocal = true;
+ }
+
+ public void addPreambleOp(SrcOp op) {
+ if ( preamble==null ) preamble = new ArrayList<SrcOp>();
+ preamble.add(op);
+ }
+
+ public void addOp(SrcOp op) {
+ if ( ops==null ) ops = new ArrayList<SrcOp>();
+ ops.add(op);
+ }
+
+ public void insertOp(int i, SrcOp op) {
+ if ( ops==null ) ops = new ArrayList<SrcOp>();
+ ops.add(i, op);
+ }
+
+ public void addOps(List<SrcOp> ops) {
+ if ( this.ops==null ) this.ops = new ArrayList<SrcOp>();
+ this.ops.addAll(ops);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/decl/ContextGetterDecl.java b/tool/src/org/antlr/v4/codegen/model/decl/ContextGetterDecl.java
new file mode 100644
index 0000000..99ceef2
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/decl/ContextGetterDecl.java
@@ -0,0 +1,68 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.decl;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.runtime.misc.MurmurHash;
+
+public abstract class ContextGetterDecl extends Decl {
+ public ContextGetterDecl(OutputModelFactory factory, String name) {
+ super(factory, name);
+ }
+
+ /** Not used for output; just used to distinguish between decl types
+ * to avoid dups.
+ */
+ public String getArgType() { return ""; }; // assume no args
+
+ @Override
+ public int hashCode() {
+ int hash = MurmurHash.initialize();
+ hash = MurmurHash.update(hash, name);
+ hash = MurmurHash.update(hash, getArgType());
+ hash = MurmurHash.finish(hash, 2);
+ return hash;
+ }
+
+ /** Make sure that a getter does not equal a label. X() and X are ok.
+ * OTOH, treat X() with two diff return values as the same. Treat
+ * two X() with diff args as different.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if ( this==obj ) return true;
+ // A() and label A are different
+ if ( !(obj instanceof ContextGetterDecl) ) return false;
+ return
+ name.equals(((Decl) obj).name) &&
+ getArgType().equals(((ContextGetterDecl) obj).getArgType());
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/decl/ContextRuleGetterDecl.java b/tool/src/org/antlr/v4/codegen/model/decl/ContextRuleGetterDecl.java
new file mode 100644
index 0000000..2bb4f9b
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/decl/ContextRuleGetterDecl.java
@@ -0,0 +1,42 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.decl;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+
+/** {@code public XContext X() { }} */
+public class ContextRuleGetterDecl extends ContextGetterDecl {
+ public String ctxName;
+ public ContextRuleGetterDecl(OutputModelFactory factory, String name, String ctxName) {
+ super(factory, name);
+ this.ctxName = ctxName;
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/decl/ContextRuleListGetterDecl.java b/tool/src/org/antlr/v4/codegen/model/decl/ContextRuleListGetterDecl.java
new file mode 100644
index 0000000..c3bfae9
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/decl/ContextRuleListGetterDecl.java
@@ -0,0 +1,44 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.decl;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+
+/** {@code public List<XContext> X() { }
+ * public XContext X(int i) { }}
+ */
+public class ContextRuleListGetterDecl extends ContextGetterDecl {
+ public String ctxName;
+ public ContextRuleListGetterDecl(OutputModelFactory factory, String name, String ctxName) {
+ super(factory, name);
+ this.ctxName = ctxName;
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/decl/ContextRuleListIndexedGetterDecl.java b/tool/src/org/antlr/v4/codegen/model/decl/ContextRuleListIndexedGetterDecl.java
new file mode 100644
index 0000000..a2c3948
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/decl/ContextRuleListIndexedGetterDecl.java
@@ -0,0 +1,44 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.decl;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+
+public class ContextRuleListIndexedGetterDecl extends ContextRuleListGetterDecl {
+ public ContextRuleListIndexedGetterDecl(OutputModelFactory factory, String name, String ctxName) {
+ super(factory, name, ctxName);
+ }
+
+ @Override
+ public String getArgType() {
+ return "int";
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/decl/ContextTokenGetterDecl.java b/tool/src/org/antlr/v4/codegen/model/decl/ContextTokenGetterDecl.java
new file mode 100644
index 0000000..431e817
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/decl/ContextTokenGetterDecl.java
@@ -0,0 +1,40 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.decl;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+
+/** {@code public Token X() { }} */
+public class ContextTokenGetterDecl extends ContextGetterDecl {
+ public ContextTokenGetterDecl(OutputModelFactory factory, String name) {
+ super(factory, name);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/decl/ContextTokenListGetterDecl.java b/tool/src/org/antlr/v4/codegen/model/decl/ContextTokenListGetterDecl.java
new file mode 100644
index 0000000..d293720
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/decl/ContextTokenListGetterDecl.java
@@ -0,0 +1,42 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.decl;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+
+/** {@code public List<Token> X() { }
+ * public Token X(int i) { }}
+ */
+public class ContextTokenListGetterDecl extends ContextGetterDecl {
+ public ContextTokenListGetterDecl(OutputModelFactory factory, String name) {
+ super(factory, name);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/decl/ContextTokenListIndexedGetterDecl.java b/tool/src/org/antlr/v4/codegen/model/decl/ContextTokenListIndexedGetterDecl.java
new file mode 100644
index 0000000..ff7e48e
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/decl/ContextTokenListIndexedGetterDecl.java
@@ -0,0 +1,44 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.decl;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+
+public class ContextTokenListIndexedGetterDecl extends ContextTokenListGetterDecl {
+ public ContextTokenListIndexedGetterDecl(OutputModelFactory factory, String name) {
+ super(factory, name);
+ }
+
+ @Override
+ public String getArgType() {
+ return "int";
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/decl/Decl.java b/tool/src/org/antlr/v4/codegen/model/decl/Decl.java
new file mode 100644
index 0000000..c956555
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/decl/Decl.java
@@ -0,0 +1,67 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.decl;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.codegen.model.SrcOp;
+
+/** */
+public class Decl extends SrcOp {
+ public String name;
+ public String decl; // whole thing if copied from action
+ public boolean isLocal; // if local var (not in RuleContext struct)
+ public StructDecl ctx; // which context contains us? set by addDecl
+
+ public Decl(OutputModelFactory factory, String name, String decl) {
+ this(factory, name);
+ this.decl = decl;
+ }
+
+ public Decl(OutputModelFactory factory, String name) {
+ super(factory);
+ this.name = name;
+ }
+
+ @Override
+ public int hashCode() {
+ return name.hashCode();
+ }
+
+ /** If same name, can't redefine, unless it's a getter */
+ @Override
+ public boolean equals(Object obj) {
+ if ( this==obj ) return true;
+ if ( !(obj instanceof Decl) ) return false;
+ // A() and label A are different
+ if ( obj instanceof ContextGetterDecl ) return false;
+ return name.equals(((Decl) obj).name);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/decl/ElementListDecl.java b/tool/src/org/antlr/v4/codegen/model/decl/ElementListDecl.java
new file mode 100644
index 0000000..cf99a1a
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/decl/ElementListDecl.java
@@ -0,0 +1,39 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.decl;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+
+public class ElementListDecl extends Decl {
+ public ElementListDecl(OutputModelFactory factory, String name) {
+ super(factory, name);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/decl/RuleContextDecl.java b/tool/src/org/antlr/v4/codegen/model/decl/RuleContextDecl.java
new file mode 100644
index 0000000..6f97bfa
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/decl/RuleContextDecl.java
@@ -0,0 +1,44 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.decl;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+
+/** */
+public class RuleContextDecl extends Decl {
+ public String ctxName;
+ public boolean isImplicit;
+
+ public RuleContextDecl(OutputModelFactory factory, String name, String ctxName) {
+ super(factory, name);
+ this.ctxName = ctxName;
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/decl/RuleContextListDecl.java b/tool/src/org/antlr/v4/codegen/model/decl/RuleContextListDecl.java
new file mode 100644
index 0000000..fbd22f6
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/decl/RuleContextListDecl.java
@@ -0,0 +1,40 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.decl;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+
+public class RuleContextListDecl extends RuleContextDecl {
+ public RuleContextListDecl(OutputModelFactory factory, String name, String ctxName) {
+ super(factory, name, ctxName);
+ isImplicit = false;
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/decl/StructDecl.java b/tool/src/org/antlr/v4/codegen/model/decl/StructDecl.java
new file mode 100644
index 0000000..309d6ca
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/decl/StructDecl.java
@@ -0,0 +1,112 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.decl;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+import org.antlr.v4.codegen.model.DispatchMethod;
+import org.antlr.v4.codegen.model.ListenerDispatchMethod;
+import org.antlr.v4.codegen.model.ModelElement;
+import org.antlr.v4.codegen.model.OutputModelObject;
+import org.antlr.v4.codegen.model.VisitorDispatchMethod;
+import org.antlr.v4.runtime.misc.OrderedHashSet;
+import org.antlr.v4.tool.Attribute;
+import org.antlr.v4.tool.Rule;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/** This object models the structure holding all of the parameters,
+ * return values, local variables, and labels associated with a rule.
+ */
+public class StructDecl extends Decl {
+ public String derivedFromName; // rule name or label name
+ public boolean provideCopyFrom;
+ @ModelElement public OrderedHashSet<Decl> attrs = new OrderedHashSet<Decl>();
+ @ModelElement public OrderedHashSet<Decl> getters = new OrderedHashSet<Decl>();
+ @ModelElement public Collection<AttributeDecl> ctorAttrs;
+ @ModelElement public List<? super DispatchMethod> dispatchMethods;
+ @ModelElement public List<OutputModelObject> interfaces;
+ @ModelElement public List<OutputModelObject> extensionMembers;
+
+ public StructDecl(OutputModelFactory factory, Rule r) {
+ super(factory, factory.getGenerator().getTarget().getRuleFunctionContextStructName(r));
+ addDispatchMethods(r);
+ derivedFromName = r.name;
+ provideCopyFrom = r.hasAltSpecificContexts();
+ }
+
+ public void addDispatchMethods(Rule r) {
+ dispatchMethods = new ArrayList<DispatchMethod>();
+ if ( !r.hasAltSpecificContexts() ) {
+ // no enter/exit for this ruleContext if rule has labels
+ if ( factory.getGrammar().tool.gen_listener ) {
+ dispatchMethods.add(new ListenerDispatchMethod(factory, true));
+ dispatchMethods.add(new ListenerDispatchMethod(factory, false));
+ }
+ if ( factory.getGrammar().tool.gen_visitor ) {
+ dispatchMethods.add(new VisitorDispatchMethod(factory));
+ }
+ }
+ }
+
+ public void addDecl(Decl d) {
+ d.ctx = this;
+ if ( d instanceof ContextGetterDecl ) getters.add(d);
+ else attrs.add(d);
+ }
+
+ public void addDecl(Attribute a) {
+ addDecl(new AttributeDecl(factory, a));
+ }
+
+ public void addDecls(Collection<Attribute> attrList) {
+ for (Attribute a : attrList) addDecl(a);
+ }
+
+ public void implementInterface(OutputModelObject value) {
+ if (interfaces == null) {
+ interfaces = new ArrayList<OutputModelObject>();
+ }
+
+ interfaces.add(value);
+ }
+
+ public void addExtensionMember(OutputModelObject member) {
+ if (extensionMembers == null) {
+ extensionMembers = new ArrayList<OutputModelObject>();
+ }
+
+ extensionMembers.add(member);
+ }
+
+ public boolean isEmpty() { return attrs.isEmpty(); }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/decl/TokenDecl.java b/tool/src/org/antlr/v4/codegen/model/decl/TokenDecl.java
new file mode 100644
index 0000000..0971fb0
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/decl/TokenDecl.java
@@ -0,0 +1,42 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.decl;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+
+/** x=ID or implicit _tID label */
+public class TokenDecl extends Decl {
+ public boolean isImplicit;
+
+ public TokenDecl(OutputModelFactory factory, String varName) {
+ super(factory, varName);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/decl/TokenListDecl.java b/tool/src/org/antlr/v4/codegen/model/decl/TokenListDecl.java
new file mode 100644
index 0000000..37b7b0e
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/decl/TokenListDecl.java
@@ -0,0 +1,40 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.decl;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+
+/** */
+public class TokenListDecl extends TokenDecl {
+ public TokenListDecl(OutputModelFactory factory, String varName) {
+ super(factory, varName);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/model/decl/TokenTypeDecl.java b/tool/src/org/antlr/v4/codegen/model/decl/TokenTypeDecl.java
new file mode 100644
index 0000000..2762ba3
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/model/decl/TokenTypeDecl.java
@@ -0,0 +1,40 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.model.decl;
+
+import org.antlr.v4.codegen.OutputModelFactory;
+
+/** */
+public class TokenTypeDecl extends Decl {
+ public TokenTypeDecl(OutputModelFactory factory, String name) {
+ super(factory, name);
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/target/CSharpTarget.java b/tool/src/org/antlr/v4/codegen/target/CSharpTarget.java
new file mode 100644
index 0000000..09df962
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/target/CSharpTarget.java
@@ -0,0 +1,177 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2013 Terence Parr
+ * Copyright (c) 2013 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.v4.codegen.target;
+
+import org.antlr.v4.codegen.CodeGenerator;
+import org.antlr.v4.codegen.Target;
+import org.antlr.v4.tool.ErrorType;
+import org.antlr.v4.tool.ast.GrammarAST;
+import org.stringtemplate.v4.NumberRenderer;
+import org.stringtemplate.v4.STErrorListener;
+import org.stringtemplate.v4.STGroup;
+import org.stringtemplate.v4.STGroupFile;
+import org.stringtemplate.v4.StringRenderer;
+import org.stringtemplate.v4.misc.STMessage;
+
+public class CSharpTarget extends Target {
+
+ public CSharpTarget(CodeGenerator gen) {
+ super(gen, "CSharp");
+ targetCharValueEscape[0] = "\\0";
+ targetCharValueEscape[0x0007] = "\\a";
+ targetCharValueEscape[0x000B] = "\\v";
+ }
+
+ @Override
+ public String getVersion() {
+ return "4.5.1"; // crossing fingers that it's close enough.
+ }
+
+ @Override
+ public String encodeIntAsCharEscape(int v) {
+ if (v < Character.MIN_VALUE || v > Character.MAX_VALUE) {
+ throw new IllegalArgumentException(String.format("Cannot encode the specified value: %d", v));
+ }
+
+ if (v >= 0 && v < targetCharValueEscape.length && targetCharValueEscape[v] != null) {
+ return targetCharValueEscape[v];
+ }
+
+ if (v >= 0x20 && v < 127 && (v < '0' || v > '9') && (v < 'a' || v > 'f') && (v < 'A' || v > 'F')) {
+ return String.valueOf((char)v);
+ }
+
+ return String.format("\\x%X", v & 0xFFFF);
+ }
+
+ @Override
+ public String getTargetStringLiteralFromANTLRStringLiteral(
+ CodeGenerator generator,
+ String literal, boolean addQuotes)
+ {
+ StringBuilder sb = new StringBuilder();
+ String is = literal;
+
+ if ( addQuotes ) sb.append('"');
+
+ for (int i = 1; i < is.length() -1; i++) {
+ if (is.charAt(i) == '\\') {
+ // Anything escaped is what it is! We assume that
+ // people know how to escape characters correctly. However
+ // we catch anything that does not need an escape in Java (which
+ // is what the default implementation is dealing with and remove
+ // the escape. The C target does this for instance.
+ //
+ switch (is.charAt(i+1)) {
+ // Pass through any escapes that Java also needs
+ //
+ case '"':
+ case 'n':
+ case 'r':
+ case 't':
+ case 'b':
+ case 'f':
+ case '\\':
+ // Pass the escape through
+ sb.append('\\');
+ break;
+
+ case 'u': // Assume unnnn
+ // Pass the escape through as double \\
+ // so that Java leaves as \u0000 string not char
+ sb.append('\\');
+ sb.append('\\');
+ break;
+
+ default:
+ // Remove the escape by virtue of not adding it here
+ // Thus \' becomes ' and so on
+ break;
+ }
+
+ // Go past the \ character
+ i++;
+ } else {
+ // Characters that don't need \ in ANTLR 'strings' but do in Java
+ if (is.charAt(i) == '"') {
+ // We need to escape " in Java
+ sb.append('\\');
+ }
+ }
+ // Add in the next character, which may have been escaped
+ sb.append(is.charAt(i));
+ }
+
+ if ( addQuotes ) sb.append('"');
+
+ return sb.toString();
+ }
+
+ @Override
+ protected boolean visibleGrammarSymbolCausesIssueInGeneratedCode(GrammarAST idNode) {
+ return false;
+ }
+
+ @Override
+ protected STGroup loadTemplates() {
+ // override the superclass behavior to put all C# templates in the same folder
+ STGroup result = new STGroupFile(CodeGenerator.TEMPLATE_ROOT+"/CSharp/"+getLanguage()+STGroup.GROUP_FILE_EXTENSION);
+ result.registerRenderer(Integer.class, new NumberRenderer());
+ result.registerRenderer(String.class, new StringRenderer());
+ result.setListener(new STErrorListener() {
+ @Override
+ public void compileTimeError(STMessage msg) {
+ reportError(msg);
+ }
+
+ @Override
+ public void runTimeError(STMessage msg) {
+ reportError(msg);
+ }
+
+ @Override
+ public void IOError(STMessage msg) {
+ reportError(msg);
+ }
+
+ @Override
+ public void internalError(STMessage msg) {
+ reportError(msg);
+ }
+
+ private void reportError(STMessage msg) {
+ getCodeGenerator().tool.errMgr.toolError(ErrorType.STRING_TEMPLATE_WARNING, msg.cause, msg.toString());
+ }
+ });
+
+ return result;
+ }
+
+}
diff --git a/tool/src/org/antlr/v4/codegen/target/JavaScriptTarget.java b/tool/src/org/antlr/v4/codegen/target/JavaScriptTarget.java
new file mode 100644
index 0000000..26fa4fe
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/target/JavaScriptTarget.java
@@ -0,0 +1,234 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.target;
+
+import org.antlr.v4.codegen.CodeGenerator;
+import org.antlr.v4.codegen.Target;
+import org.antlr.v4.tool.ast.GrammarAST;
+import org.stringtemplate.v4.STGroup;
+import org.stringtemplate.v4.StringRenderer;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.Set;
+
+/**
+ *
+ * @author Eric Vergnaud
+ */
+public class JavaScriptTarget extends Target {
+
+ /** Source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar */
+ protected static final String[] javaScriptKeywords = {
+ "break", "case", "class", "catch", "const", "continue", "debugger",
+ "default", "delete", "do", "else", "export", "extends", "finally", "for",
+ "function", "if", "import", "in", "instanceof", "let", "new", "return",
+ "super", "switch", "this", "throw", "try", "typeof", "var", "void",
+ "while", "with", "yield",
+ //future reserved
+ "enum", "await", "implements", "package", "protected", "static",
+ "interface", "private", "public",
+ //future reserved in older standards
+ "abstract", "boolean", "byte", "char", "double", "final", "float",
+ "goto", "int", "long", "native", "short", "synchronized", "transient",
+ "volatile",
+ //literals
+ "null", "true", "false"
+ };
+
+ /** Avoid grammar symbols in this set to prevent conflicts in gen'd code. */
+ protected final Set<String> badWords = new HashSet<String>();
+
+ public JavaScriptTarget(CodeGenerator gen) {
+ super(gen, "JavaScript");
+ }
+
+ @Override
+ public String getVersion() {
+ return "4.5.1";
+ }
+
+ public Set<String> getBadWords() {
+ if (badWords.isEmpty()) {
+ addBadWords();
+ }
+
+ return badWords;
+ }
+
+ protected void addBadWords() {
+ badWords.addAll(Arrays.asList(javaScriptKeywords));
+ badWords.add("rule");
+ badWords.add("parserRule");
+ }
+
+ /**
+ * {@inheritDoc}
+ * <p/>
+ * For Java, this is the translation {@code 'a\n"'} &rarr; {@code "a\n\""}.
+ * Expect single quotes around the incoming literal. Just flip the quotes
+ * and replace double quotes with {@code \"}.
+ * <p/>
+ * Note that we have decided to allow people to use '\"' without penalty, so
+ * we must build the target string in a loop as {@link String#replace}
+ * cannot handle both {@code \"} and {@code "} without a lot of messing
+ * around.
+ */
+ @Override
+ public String getTargetStringLiteralFromANTLRStringLiteral(
+ CodeGenerator generator,
+ String literal, boolean addQuotes)
+ {
+ StringBuilder sb = new StringBuilder();
+ String is = literal;
+
+ if ( addQuotes ) sb.append('"');
+
+ for (int i = 1; i < is.length() -1; i++) {
+ if (is.charAt(i) == '\\') {
+ // Anything escaped is what it is! We assume that
+ // people know how to escape characters correctly. However
+ // we catch anything that does not need an escape in Java (which
+ // is what the default implementation is dealing with and remove
+ // the escape. The C target does this for instance.
+ //
+ switch (is.charAt(i+1)) {
+ // Pass through any escapes that Java also needs
+ //
+ case '"':
+ case 'n':
+ case 'r':
+ case 't':
+ case 'b':
+ case 'f':
+ case '\\':
+ // Pass the escape through
+ sb.append('\\');
+ break;
+
+ case 'u': // Assume unnnn
+ // Pass the escape through as double \\
+ // so that Java leaves as \u0000 string not char
+ sb.append('\\');
+ sb.append('\\');
+ break;
+
+ default:
+ // Remove the escape by virtue of not adding it here
+ // Thus \' becomes ' and so on
+ break;
+ }
+
+ // Go past the \ character
+ i++;
+ } else {
+ // Characters that don't need \ in ANTLR 'strings' but do in Java
+ if (is.charAt(i) == '"') {
+ // We need to escape " in Java
+ sb.append('\\');
+ }
+ }
+ // Add in the next character, which may have been escaped
+ sb.append(is.charAt(i));
+ }
+
+ if ( addQuotes ) sb.append('"');
+
+ return sb.toString();
+ }
+
+ @Override
+ public String encodeIntAsCharEscape(int v) {
+ if (v < Character.MIN_VALUE || v > Character.MAX_VALUE) {
+ throw new IllegalArgumentException(String.format("Cannot encode the specified value: %d", v));
+ }
+
+ if (v >= 0 && v < targetCharValueEscape.length && targetCharValueEscape[v] != null) {
+ return targetCharValueEscape[v];
+ }
+
+ if (v >= 0x20 && v < 127) {
+ return String.valueOf((char)v);
+ }
+
+ String hex = Integer.toHexString(v|0x10000).substring(1,5);
+ return "\\u"+hex;
+ }
+
+ @Override
+ public int getSerializedATNSegmentLimit() {
+ return 2 ^ 31;
+ }
+
+ @Override
+ public int getInlineTestSetWordSize() {
+ return 32;
+ }
+
+ @Override
+ protected boolean visibleGrammarSymbolCausesIssueInGeneratedCode(GrammarAST idNode) {
+ return getBadWords().contains(idNode.getText());
+ }
+
+ @Override
+ protected STGroup loadTemplates() {
+ STGroup result = super.loadTemplates();
+ result.registerRenderer(String.class, new JavaStringRenderer(), true);
+ return result;
+ }
+
+ protected static class JavaStringRenderer extends StringRenderer {
+
+ @Override
+ public String toString(Object o, String formatString, Locale locale) {
+ if ("java-escape".equals(formatString)) {
+ // 5C is the hex code for the \ itself
+ return ((String)o).replace("\\u", "\\u005Cu");
+ }
+
+ return super.toString(o, formatString, locale);
+ }
+
+ }
+
+ public boolean wantsBaseListener() {
+ return false;
+ }
+
+ public boolean wantsBaseVisitor() {
+ return false;
+ }
+
+ public boolean supportsOverloadedMethods() {
+ return false;
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/target/JavaTarget.java b/tool/src/org/antlr/v4/codegen/target/JavaTarget.java
new file mode 100644
index 0000000..6ee18da
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/target/JavaTarget.java
@@ -0,0 +1,126 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.target;
+
+import org.antlr.v4.Tool;
+import org.antlr.v4.codegen.CodeGenerator;
+import org.antlr.v4.codegen.Target;
+import org.antlr.v4.tool.ast.GrammarAST;
+import org.stringtemplate.v4.STGroup;
+import org.stringtemplate.v4.StringRenderer;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.Set;
+
+public class JavaTarget extends Target {
+
+ /**
+ * The Java target can cache the code generation templates.
+ */
+ private static final ThreadLocal<STGroup> targetTemplates = new ThreadLocal<STGroup>();
+
+ protected static final String[] javaKeywords = {
+ "abstract", "assert", "boolean", "break", "byte", "case", "catch",
+ "char", "class", "const", "continue", "default", "do", "double", "else",
+ "enum", "extends", "false", "final", "finally", "float", "for", "goto",
+ "if", "implements", "import", "instanceof", "int", "interface",
+ "long", "native", "new", "null", "package", "private", "protected",
+ "public", "return", "short", "static", "strictfp", "super", "switch",
+ "synchronized", "this", "throw", "throws", "transient", "true", "try",
+ "void", "volatile", "while"
+ };
+
+ /** Avoid grammar symbols in this set to prevent conflicts in gen'd code. */
+ protected final Set<String> badWords = new HashSet<String>();
+
+ public JavaTarget(CodeGenerator gen) {
+ super(gen, "Java");
+ }
+
+ @Override
+ public String getVersion() {
+ return Tool.VERSION; // Java and tool versions move in lock step
+ }
+
+ public Set<String> getBadWords() {
+ if (badWords.isEmpty()) {
+ addBadWords();
+ }
+
+ return badWords;
+ }
+
+ protected void addBadWords() {
+ badWords.addAll(Arrays.asList(javaKeywords));
+ badWords.add("rule");
+ badWords.add("parserRule");
+ }
+
+ @Override
+ public int getSerializedATNSegmentLimit() {
+ // 65535 is the class file format byte limit for a UTF-8 encoded string literal
+ // 3 is the maximum number of bytes it takes to encode a value in the range 0-0xFFFF
+ return 65535 / 3;
+ }
+
+ @Override
+ protected boolean visibleGrammarSymbolCausesIssueInGeneratedCode(GrammarAST idNode) {
+ return getBadWords().contains(idNode.getText());
+ }
+
+ @Override
+ protected STGroup loadTemplates() {
+ STGroup result = targetTemplates.get();
+ if (result == null) {
+ result = super.loadTemplates();
+ result.registerRenderer(String.class, new JavaStringRenderer(), true);
+ targetTemplates.set(result);
+ }
+
+ return result;
+ }
+
+ protected static class JavaStringRenderer extends StringRenderer {
+
+ @Override
+ public String toString(Object o, String formatString, Locale locale) {
+ if ("java-escape".equals(formatString)) {
+ // 5C is the hex code for the \ itself
+ return ((String)o).replace("\\u", "\\u005Cu");
+ }
+
+ return super.toString(o, formatString, locale);
+ }
+
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/target/Python2Target.java b/tool/src/org/antlr/v4/codegen/target/Python2Target.java
new file mode 100644
index 0000000..36249d5
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/target/Python2Target.java
@@ -0,0 +1,136 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.target;
+
+import org.antlr.v4.codegen.CodeGenerator;
+import org.antlr.v4.codegen.Target;
+import org.antlr.v4.tool.ast.GrammarAST;
+import org.stringtemplate.v4.STGroup;
+import org.stringtemplate.v4.StringRenderer;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.Set;
+
+/**
+ *
+ * @author Eric Vergnaud
+ */
+public class Python2Target extends Target {
+ protected static final String[] python2Keywords = {
+ "abs", "all", "any", "apply", "as",
+ "bin", "bool", "buffer", "bytearray",
+ "callable", "chr", "classmethod", "coerce", "compile", "complex",
+ "delattr", "dict", "dir", "divmod",
+ "enumerate", "eval", "execfile",
+ "file", "filter", "float", "format", "frozenset",
+ "getattr", "globals",
+ "hasattr", "hash", "help", "hex",
+ "id", "input", "int", "intern", "isinstance", "issubclass", "iter",
+ "len", "list", "locals",
+ "map", "max", "min", "next",
+ "memoryview",
+ "object", "oct", "open", "ord",
+ "pow", "print", "property",
+ "range", "raw_input", "reduce", "reload", "repr", "reversed", "round",
+ "set", "setattr", "slice", "sorted", "staticmethod", "str", "sum", "super",
+ "tuple", "type",
+ "unichr", "unicode",
+ "vars",
+ "with",
+ "xrange",
+ "zip",
+ "__import__",
+ "True", "False", "None"
+ };
+
+ /** Avoid grammar symbols in this set to prevent conflicts in gen'd code. */
+ protected final Set<String> badWords = new HashSet<String>();
+
+ public Python2Target(CodeGenerator gen) {
+ super(gen, "Python2");
+ }
+
+ @Override
+ protected boolean visibleGrammarSymbolCausesIssueInGeneratedCode(GrammarAST idNode) {
+ return getBadWords().contains(idNode.getText());
+ }
+
+ @Override
+ protected STGroup loadTemplates() {
+ STGroup result = super.loadTemplates();
+ result.registerRenderer(String.class, new PythonStringRenderer(), true);
+ return result;
+ }
+
+ protected static class PythonStringRenderer extends StringRenderer {
+
+ @Override
+ public String toString(Object o, String formatString, Locale locale) {
+ return super.toString(o, formatString, locale);
+ }
+ }
+
+ @Override
+ public boolean wantsBaseListener() {
+ return false;
+ }
+
+ @Override
+ public boolean wantsBaseVisitor() {
+ return false;
+ }
+
+ @Override
+ public boolean supportsOverloadedMethods() {
+ return false;
+ }
+
+ @Override
+ public String getVersion() {
+ return "4.5.2";
+ }
+
+ public Set<String> getBadWords() {
+ if (badWords.isEmpty()) {
+ addBadWords();
+ }
+
+ return badWords;
+ }
+
+ protected void addBadWords() {
+ badWords.addAll(Arrays.asList(python2Keywords));
+ badWords.add("rule");
+ badWords.add("parserRule");
+ }
+}
diff --git a/tool/src/org/antlr/v4/codegen/target/Python3Target.java b/tool/src/org/antlr/v4/codegen/target/Python3Target.java
new file mode 100644
index 0000000..d07247f
--- /dev/null
+++ b/tool/src/org/antlr/v4/codegen/target/Python3Target.java
@@ -0,0 +1,143 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.codegen.target;
+
+import org.antlr.v4.codegen.CodeGenerator;
+import org.antlr.v4.codegen.Target;
+import org.antlr.v4.tool.ast.GrammarAST;
+import org.stringtemplate.v4.STGroup;
+import org.stringtemplate.v4.StringRenderer;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.Set;
+
+/**
+ *
+ * @author Eric Vergnaud
+ */
+public class Python3Target extends Target {
+ protected static final String[] python3Keywords = {
+ "abs", "all", "any", "apply", "as",
+ "bin", "bool", "buffer", "bytearray",
+ "callable", "chr", "classmethod", "coerce", "compile", "complex",
+ "delattr", "dict", "dir", "divmod",
+ "enumerate", "eval", "execfile",
+ "file", "filter", "float", "format", "frozenset",
+ "getattr", "globals",
+ "hasattr", "hash", "help", "hex",
+ "id", "input", "int", "intern", "isinstance", "issubclass", "iter",
+ "len", "list", "locals",
+ "map", "max", "min", "next",
+ "memoryview",
+ "object", "oct", "open", "ord",
+ "pow", "print", "property",
+ "range", "raw_input", "reduce", "reload", "repr", "reversed", "round",
+ "set", "setattr", "slice", "sorted", "staticmethod", "str", "sum", "super",
+ "tuple", "type",
+ "unichr", "unicode",
+ "vars",
+ "with",
+ "zip",
+ "__import__",
+ "True", "False", "None"
+ };
+
+ public Python3Target(CodeGenerator gen) {
+ super(gen, "Python3");
+ }
+
+ @Override
+ public int getSerializedATNSegmentLimit() {
+ // set to something stupid to avoid segmentation
+ return 2 ^ 31;
+ }
+
+ @Override
+ protected boolean visibleGrammarSymbolCausesIssueInGeneratedCode(GrammarAST idNode) {
+ return getBadWords().contains(idNode.getText());
+ }
+
+ @Override
+ protected STGroup loadTemplates() {
+ STGroup result = super.loadTemplates();
+ result.registerRenderer(String.class, new PythonStringRenderer(), true);
+ return result;
+ }
+
+ protected static class PythonStringRenderer extends StringRenderer {
+
+ @Override
+ public String toString(Object o, String formatString, Locale locale) {
+ return super.toString(o, formatString, locale);
+ }
+ }
+
+ @Override
+ public boolean wantsBaseListener() {
+ return false;
+ }
+
+ @Override
+ public boolean wantsBaseVisitor() {
+ return false;
+ }
+
+ @Override
+ public boolean supportsOverloadedMethods() {
+ return false;
+ }
+
+ @Override
+ public String getVersion() {
+ return "4.5.2";
+ }
+
+ /** Avoid grammar symbols in this set to prevent conflicts in gen'd code. */
+ protected final Set<String> badWords = new HashSet<String>();
+
+ public Set<String> getBadWords() {
+ if (badWords.isEmpty()) {
+ addBadWords();
+ }
+
+ return badWords;
+ }
+
+ protected void addBadWords() {
+ badWords.addAll(Arrays.asList(python3Keywords));
+ badWords.add("rule");
+ badWords.add("parserRule");
+ }
+
+
+}
diff --git a/tool/src/org/antlr/v4/gui/BasicFontMetrics.java b/tool/src/org/antlr/v4/gui/BasicFontMetrics.java
new file mode 100644
index 0000000..b424a00
--- /dev/null
+++ b/tool/src/org/antlr/v4/gui/BasicFontMetrics.java
@@ -0,0 +1,95 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.gui;
+
+/** Font metrics. The only way to generate accurate images
+ * in any format that contain text is to know the font metrics.
+ * Specifically, we need to know the width of every character and the
+ * maximum height (since we want all characters to fit within same line height).
+ * I used ttf2tfm to dump the font metrics from Mac TrueType fonts and
+ * then converted that to a Java class for use in a PostScript generator
+ * for trees. Commands:
+ *
+ * <pre>
+ * $ ttf2tfm /Library/Fonts/Arial\ Black.ttf &gt; metrics
+ * </pre>
+ *
+ * Then run metrics into python code after stripping header/footer:
+ *
+ * <pre>
+ * #
+ * # Process lines from ttf2tfm that look like this:
+ * # Glyph Code Glyph Name Width llx lly urx ury
+ * # ------------------------------------------------------------------------
+ * # 3 00020 space 333 0, 0 -- 0, 0
+ * #
+ * lines = open("metrics").read().split('\n')
+ * print "public class FontName {"
+ * print " {"
+ * maxh = 0;
+ * for line in lines[4:]: # skip header 0..3
+ * all = line.split(' ')
+ * words = [x for x in all if len(x)&gt;0]
+ * ascii = int(words[1], 16)
+ * height = int(words[8])
+ * if height&gt;maxh: maxh = height
+ * if ascii&gt;=128: break
+ * print " widths[%d] = %s; // %s" % (ascii, words[3], words[2])
+ *
+ * print " maxCharHeight = "+str(maxh)+";"
+ * print " }"
+ * print "}"
+ * </pre>
+ *
+ * Units are 1000th of an 'em'.
+ */
+public abstract class BasicFontMetrics {
+ public static final int MAX_CHAR = '\u00FF';
+ protected int maxCharHeight;
+ protected int[] widths = new int[MAX_CHAR+1];
+
+ public double getWidth(String s, int fontSize) {
+ double w = 0;
+ for (char c : s.toCharArray()) {
+ w += getWidth(c, fontSize);
+ }
+ return w;
+ }
+
+ public double getWidth(char c, int fontSize) {
+ if ( c > MAX_CHAR || widths[c]==0 ) return widths['m']/1000.0; // return width('m')
+ return widths[c]/1000.0 * fontSize;
+ }
+
+ public double getLineHeight(int fontSize) {
+ return maxCharHeight / 1000.0 * fontSize;
+ }
+}
diff --git a/tool/src/org/antlr/v4/gui/GraphicsSupport.java b/tool/src/org/antlr/v4/gui/GraphicsSupport.java
new file mode 100644
index 0000000..eb9546d
--- /dev/null
+++ b/tool/src/org/antlr/v4/gui/GraphicsSupport.java
@@ -0,0 +1,138 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.gui;
+
+import javax.imageio.ImageIO;
+import javax.print.DocFlavor;
+import javax.print.DocPrintJob;
+import javax.print.PrintException;
+import javax.print.PrintService;
+import javax.print.SimpleDoc;
+import javax.print.StreamPrintServiceFactory;
+import javax.print.attribute.HashPrintRequestAttributeSet;
+import javax.print.attribute.PrintRequestAttributeSet;
+import javax.swing.*;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.awt.print.PageFormat;
+import java.awt.print.Printable;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Arrays;
+
+public class GraphicsSupport {
+ /**
+ [The "BSD license"]
+ Copyright (c) 2011 Cay Horstmann
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+ public static void saveImage(final JComponent comp, String fileName)
+ throws IOException, PrintException
+ {
+ if ( fileName.endsWith(".ps") || fileName.endsWith(".eps") ) {
+ DocFlavor flavor = DocFlavor.SERVICE_FORMATTED.PRINTABLE;
+ String mimeType = "application/postscript";
+ StreamPrintServiceFactory[] factories =
+ StreamPrintServiceFactory.lookupStreamPrintServiceFactories(flavor, mimeType);
+ System.out.println(Arrays.toString(factories));
+ if (factories.length > 0) {
+ FileOutputStream out = new FileOutputStream(fileName);
+ PrintService service = factories[0].getPrintService(out);
+ SimpleDoc doc = new SimpleDoc(new Printable() {
+ @Override
+ public int print(Graphics g, PageFormat pf, int page) {
+ if (page >= 1) return Printable.NO_SUCH_PAGE;
+ else {
+ Graphics2D g2 = (Graphics2D) g;
+ g2.translate((pf.getWidth() - pf.getImageableWidth()) / 2,
+ (pf.getHeight() - pf.getImageableHeight()) / 2);
+ if ( comp.getWidth() > pf.getImageableWidth() ||
+ comp.getHeight() > pf.getImageableHeight() )
+ {
+ double sf1 = pf.getImageableWidth() / (comp.getWidth() + 1);
+ double sf2 = pf.getImageableHeight() / (comp.getHeight() + 1);
+ double s = Math.min(sf1, sf2);
+ g2.scale(s, s);
+ }
+
+ comp.paint(g);
+ return Printable.PAGE_EXISTS;
+ }
+ }
+ }, flavor, null);
+ DocPrintJob job = service.createPrintJob();
+ PrintRequestAttributeSet attributes = new HashPrintRequestAttributeSet();
+ job.print(doc, attributes);
+ out.close();
+ }
+ } else {
+ // parrt: works with [image/jpeg, image/png, image/x-png, image/vnd.wap.wbmp, image/bmp, image/gif]
+ Rectangle rect = comp.getBounds();
+ BufferedImage image = new BufferedImage(rect.width, rect.height,
+ BufferedImage.TYPE_INT_RGB);
+ Graphics2D g = (Graphics2D) image.getGraphics();
+ g.setColor(Color.WHITE);
+ g.fill(rect);
+// g.setColor(Color.BLACK);
+ comp.paint(g);
+ String extension = fileName.substring(fileName.lastIndexOf('.') + 1);
+ boolean result = ImageIO.write(image, extension, new File(fileName));
+ if ( !result ) {
+ System.err.println("Now imager for " + extension);
+ }
+ g.dispose();
+ }
+ }
+}
diff --git a/tool/src/org/antlr/v4/gui/JFileChooserConfirmOverwrite.java b/tool/src/org/antlr/v4/gui/JFileChooserConfirmOverwrite.java
new file mode 100644
index 0000000..59cbb69
--- /dev/null
+++ b/tool/src/org/antlr/v4/gui/JFileChooserConfirmOverwrite.java
@@ -0,0 +1,63 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2013 Terence Parr
+ * Copyright (c) 2013 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.v4.gui;
+
+import javax.swing.*;
+import java.io.File;
+
+/**
+ *
+ * @author Sam Harwell
+ */
+public class JFileChooserConfirmOverwrite extends JFileChooser {
+
+ public JFileChooserConfirmOverwrite() {
+ setMultiSelectionEnabled(false);
+ }
+
+ @Override
+ public void approveSelection() {
+ File selectedFile = getSelectedFile();
+
+ if (selectedFile.exists()) {
+ int answer = JOptionPane.showConfirmDialog(this,
+ "Overwrite existing file?",
+ "Overwrite?",
+ JOptionPane.YES_NO_OPTION);
+ if (answer != JOptionPane.YES_OPTION) {
+ // do not call super.approveSelection
+ return;
+ }
+ }
+
+ super.approveSelection();
+ }
+
+}
diff --git a/tool/src/org/antlr/v4/gui/PostScriptDocument.java b/tool/src/org/antlr/v4/gui/PostScriptDocument.java
new file mode 100644
index 0000000..7faf2db
--- /dev/null
+++ b/tool/src/org/antlr/v4/gui/PostScriptDocument.java
@@ -0,0 +1,212 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.gui;
+
+import java.awt.*;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+
+public class PostScriptDocument {
+ public static final String DEFAULT_FONT = "CourierNew";
+
+ public static final Map<String, String> POSTSCRIPT_FONT_NAMES;
+ static {
+ POSTSCRIPT_FONT_NAMES = new HashMap<String, String>();
+ POSTSCRIPT_FONT_NAMES.put(Font.SANS_SERIF + ".plain", "ArialMT");
+ POSTSCRIPT_FONT_NAMES.put(Font.SANS_SERIF + ".bold", "Arial-BoldMT");
+ POSTSCRIPT_FONT_NAMES.put(Font.SANS_SERIF + ".italic", "Arial-ItalicMT");
+ POSTSCRIPT_FONT_NAMES.put(Font.SANS_SERIF + ".bolditalic", "Arial-BoldItalicMT");
+ POSTSCRIPT_FONT_NAMES.put(Font.SERIF + ".plain", "TimesNewRomanPSMT");
+ POSTSCRIPT_FONT_NAMES.put(Font.SERIF + ".bold", "TimesNewRomanPS-BoldMT");
+ POSTSCRIPT_FONT_NAMES.put(Font.SERIF + ".italic", "TimesNewRomanPS-ItalicMT");
+ POSTSCRIPT_FONT_NAMES.put(Font.SERIF + ".bolditalic", "TimesNewRomanPS-BoldItalicMT");
+ POSTSCRIPT_FONT_NAMES.put(Font.MONOSPACED + ".plain", "CourierNewPSMT");
+ POSTSCRIPT_FONT_NAMES.put(Font.MONOSPACED + ".bold", "CourierNewPS-BoldMT");
+ POSTSCRIPT_FONT_NAMES.put(Font.MONOSPACED + ".italic", "CourierNewPS-ItalicMT");
+ POSTSCRIPT_FONT_NAMES.put(Font.MONOSPACED + ".bolditalic", "CourierNewPS-BoldItalicMT");
+ }
+
+ protected int boundingBoxWidth;
+ protected int boundingBoxHeight;
+
+ protected SystemFontMetrics fontMetrics;
+ protected String fontName;
+ protected int fontSize = 12;
+ protected double lineWidth = 0.3;
+ protected String boundingBox;
+
+ protected StringBuilder ps = new StringBuilder();
+ protected boolean closed = false;
+
+ public PostScriptDocument() {
+ this(DEFAULT_FONT, 12);
+ }
+
+ public PostScriptDocument(String fontName, int fontSize) {
+ header();
+ setFont(fontName, fontSize);
+ }
+
+ public String getPS() {
+ close();
+ return header()+ps.toString();
+ }
+
+ public void boundingBox(int w, int h) {
+ boundingBoxWidth = w;
+ boundingBoxHeight = h;
+ boundingBox = String.format(Locale.US, "%%%%BoundingBox: %d %d %d %d\n", 0,0,
+ boundingBoxWidth,boundingBoxHeight);
+ }
+
+ public void close() {
+ if ( closed ) return;
+// ps.append("showpage\n");
+ ps.append("%%Trailer\n");
+ closed = true;
+ }
+
+ /** Compute the header separately because we need to wait for the bounding box */
+ protected StringBuilder header() {
+ StringBuilder b = new StringBuilder();
+ b.append("%!PS-Adobe-3.0 EPSF-3.0\n");
+ b.append(boundingBox).append("\n");
+ b.append("0.3 setlinewidth\n");
+ b.append("%% x y w h highlight\n" +
+ "/highlight {\n" +
+ " 4 dict begin\n" +
+ " /h exch def\n" +
+ " /w exch def\n" +
+ " /y exch def\n" +
+ " /x exch def\n" +
+ " gsave\n" +
+ " newpath\n" +
+ " x y moveto\n" +
+ " 0 h rlineto % up to left corner\n" +
+ " w 0 rlineto % to upper right corner\n" +
+ " 0 h neg rlineto % to lower right corner\n" +
+ " w neg 0 rlineto % back home to lower left corner\n" +
+ " closepath\n" +
+ " .95 .83 .82 setrgbcolor\n" +
+ " fill\n" +
+ " grestore\n" +
+ " end\n" +
+ "} def\n");
+
+ return b;
+ }
+
+ public void setFont(String fontName, int fontSize) {
+ this.fontMetrics = new SystemFontMetrics(fontName);
+ this.fontName = fontMetrics.getFont().getPSName();
+ this.fontSize = fontSize;
+
+ String psname = POSTSCRIPT_FONT_NAMES.get(this.fontName);
+ if (psname == null) {
+ psname = this.fontName;
+ }
+
+ ps.append(String.format(Locale.US, "/%s findfont %d scalefont setfont\n", psname, fontSize));
+ }
+
+ public void lineWidth(double w) {
+ lineWidth = w;
+ ps.append(w).append(" setlinewidth\n");
+ }
+
+ public void move(double x, double y) {
+ ps.append(String.format(Locale.US, "%1.3f %1.3f moveto\n", x, y));
+ }
+
+ public void lineto(double x, double y) {
+ ps.append(String.format(Locale.US, "%1.3f %1.3f lineto\n", x, y));
+ }
+
+ public void line(double x1, double y1, double x2, double y2) {
+ move(x1, y1);
+ lineto(x2, y2);
+ }
+
+ public void rect(double x, double y, double width, double height) {
+ line(x, y, x, y + height);
+ line(x, y + height, x + width, y + height);
+ line(x + width, y + height, x + width, y);
+ line(x + width, y, x, y);
+ }
+
+ /** Make red box */
+ public void highlight(double x, double y, double width, double height) {
+ ps.append(String.format(Locale.US, "%1.3f %1.3f %1.3f %1.3f highlight\n", x, y, width, height));
+ }
+
+ public void stroke() {
+ ps.append("stroke\n");
+ }
+
+// public void rarrow(double x, double y) {
+// ps.append(String.format(Locale.US, "%1.3f %1.3f rarrow\n", x,y));
+// }
+//
+// public void darrow(double x, double y) {
+// ps.append(String.format(Locale.US, "%1.3f %1.3f darrow\n", x,y));
+// }
+
+ public void text(String s, double x, double y) {
+ StringBuilder buf = new StringBuilder();
+ // escape \, (, ): \\, \(, \)
+ for (char c : s.toCharArray()) {
+ switch ( c ) {
+ case '\\' :
+ case '(' :
+ case ')' :
+ buf.append('\\');
+ buf.append(c);
+ break;
+ default :
+ buf.append(c);
+ break;
+ }
+ }
+ s = buf.toString();
+ move(x,y);
+ ps.append(String.format(Locale.US, "(%s) show\n", s));
+ stroke();
+ }
+
+ // courier new: wid/hei 7.611979 10.0625
+ /** All chars are 600 thousands of an 'em' wide if courier */
+ public double getWidth(char c) { return fontMetrics.getWidth(c, fontSize); }
+ public double getWidth(String s) { return fontMetrics.getWidth(s, fontSize); }
+ public double getLineHeight() { return fontMetrics.getLineHeight(fontSize); }
+
+ public int getFontSize() { return fontSize; }
+}
diff --git a/tool/src/org/antlr/v4/gui/SystemFontMetrics.java b/tool/src/org/antlr/v4/gui/SystemFontMetrics.java
new file mode 100644
index 0000000..fb2b17a
--- /dev/null
+++ b/tool/src/org/antlr/v4/gui/SystemFontMetrics.java
@@ -0,0 +1,63 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.gui;
+
+import java.awt.*;
+import java.awt.font.FontRenderContext;
+import java.awt.font.TextLayout;
+import java.awt.image.BufferedImage;
+
+/**
+ *
+ * @author Sam Harwell
+ */
+public class SystemFontMetrics extends BasicFontMetrics {
+ protected final Font font;
+
+ public SystemFontMetrics(String fontName) {
+ BufferedImage img = new BufferedImage(40, 40, BufferedImage.TYPE_4BYTE_ABGR);
+ Graphics2D graphics = GraphicsEnvironment.getLocalGraphicsEnvironment().createGraphics(img);
+ FontRenderContext fontRenderContext = graphics.getFontRenderContext();
+ this.font = new Font(fontName, Font.PLAIN, 1000);
+ double maxHeight = 0;
+ for (int i = 0; i < 255; i++) {
+ TextLayout layout = new TextLayout(Character.toString((char)i), font, fontRenderContext);
+ maxHeight = Math.max(maxHeight, layout.getBounds().getHeight());
+ super.widths[i] = (int)layout.getAdvance();
+ }
+
+ super.maxCharHeight = (int)Math.round(maxHeight);
+ }
+
+ public Font getFont() {
+ return font;
+ }
+}
diff --git a/tool/src/org/antlr/v4/gui/TestRig.java b/tool/src/org/antlr/v4/gui/TestRig.java
new file mode 100644
index 0000000..4812e5c
--- /dev/null
+++ b/tool/src/org/antlr/v4/gui/TestRig.java
@@ -0,0 +1,270 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.gui;
+
+import org.antlr.v4.runtime.ANTLRInputStream;
+import org.antlr.v4.runtime.CharStream;
+import org.antlr.v4.runtime.CommonTokenStream;
+import org.antlr.v4.runtime.DiagnosticErrorListener;
+import org.antlr.v4.runtime.Lexer;
+import org.antlr.v4.runtime.Parser;
+import org.antlr.v4.runtime.ParserRuleContext;
+import org.antlr.v4.runtime.TokenStream;
+import org.antlr.v4.runtime.atn.PredictionMode;
+
+import javax.print.PrintException;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+/** Run a lexer/parser combo, optionally printing tree string or generating
+ * postscript file. Optionally taking input file.
+ *
+ * $ java org.antlr.v4.runtime.misc.TestRig GrammarName startRuleName
+ * [-tree]
+ * [-tokens] [-gui] [-ps file.ps]
+ * [-trace]
+ * [-diagnostics]
+ * [-SLL]
+ * [input-filename(s)]
+ */
+public class TestRig {
+ public static final String LEXER_START_RULE_NAME = "tokens";
+
+ protected String grammarName;
+ protected String startRuleName;
+ protected final List<String> inputFiles = new ArrayList<String>();
+ protected boolean printTree = false;
+ protected boolean gui = false;
+ protected String psFile = null;
+ protected boolean showTokens = false;
+ protected boolean trace = false;
+ protected boolean diagnostics = false;
+ protected String encoding = null;
+ protected boolean SLL = false;
+
+ public TestRig(String[] args) throws Exception {
+ if ( args.length < 2 ) {
+ System.err.println("java org.antlr.v4.runtime.misc.TestRig GrammarName startRuleName\n" +
+ " [-tokens] [-tree] [-gui] [-ps file.ps] [-encoding encodingname]\n" +
+ " [-trace] [-diagnostics] [-SLL]\n"+
+ " [input-filename(s)]");
+ System.err.println("Use startRuleName='tokens' if GrammarName is a lexer grammar.");
+ System.err.println("Omitting input-filename makes rig read from stdin.");
+ return;
+ }
+ int i=0;
+ grammarName = args[i];
+ i++;
+ startRuleName = args[i];
+ i++;
+ while ( i<args.length ) {
+ String arg = args[i];
+ i++;
+ if ( arg.charAt(0)!='-' ) { // input file name
+ inputFiles.add(arg);
+ continue;
+ }
+ if ( arg.equals("-tree") ) {
+ printTree = true;
+ }
+ if ( arg.equals("-gui") ) {
+ gui = true;
+ }
+ if ( arg.equals("-tokens") ) {
+ showTokens = true;
+ }
+ else if ( arg.equals("-trace") ) {
+ trace = true;
+ }
+ else if ( arg.equals("-SLL") ) {
+ SLL = true;
+ }
+ else if ( arg.equals("-diagnostics") ) {
+ diagnostics = true;
+ }
+ else if ( arg.equals("-encoding") ) {
+ if ( i>=args.length ) {
+ System.err.println("missing encoding on -encoding");
+ return;
+ }
+ encoding = args[i];
+ i++;
+ }
+ else if ( arg.equals("-ps") ) {
+ if ( i>=args.length ) {
+ System.err.println("missing filename on -ps");
+ return;
+ }
+ psFile = args[i];
+ i++;
+ }
+ }
+ }
+
+ public static void main(String[] args) throws Exception {
+ TestRig testRig = new TestRig(args);
+ if(args.length >= 2) {
+ testRig.process();
+ }
+ }
+
+ public void process() throws Exception {
+// System.out.println("exec "+grammarName+"."+startRuleName);
+ String lexerName = grammarName+"Lexer";
+ ClassLoader cl = Thread.currentThread().getContextClassLoader();
+ Class<? extends Lexer> lexerClass = null;
+ try {
+ lexerClass = cl.loadClass(lexerName).asSubclass(Lexer.class);
+ }
+ catch (java.lang.ClassNotFoundException cnfe) {
+ // might be pure lexer grammar; no Lexer suffix then
+ lexerName = grammarName;
+ try {
+ lexerClass = cl.loadClass(lexerName).asSubclass(Lexer.class);
+ }
+ catch (ClassNotFoundException cnfe2) {
+ System.err.println("Can't load "+lexerName+" as lexer or parser");
+ return;
+ }
+ }
+
+ Constructor<? extends Lexer> lexerCtor = lexerClass.getConstructor(CharStream.class);
+ Lexer lexer = lexerCtor.newInstance((CharStream)null);
+
+ Class<? extends Parser> parserClass = null;
+ Parser parser = null;
+ if ( !startRuleName.equals(LEXER_START_RULE_NAME) ) {
+ String parserName = grammarName+"Parser";
+ parserClass = cl.loadClass(parserName).asSubclass(Parser.class);
+ if ( parserClass==null ) {
+ System.err.println("Can't load "+parserName);
+ }
+ Constructor<? extends Parser> parserCtor = parserClass.getConstructor(TokenStream.class);
+ parser = parserCtor.newInstance((TokenStream)null);
+ }
+
+ if ( inputFiles.size()==0 ) {
+ InputStream is = System.in;
+ Reader r;
+ if ( encoding!=null ) {
+ r = new InputStreamReader(is, encoding);
+ }
+ else {
+ r = new InputStreamReader(is);
+ }
+
+ process(lexer, parserClass, parser, is, r);
+ return;
+ }
+ for (String inputFile : inputFiles) {
+ InputStream is = System.in;
+ if ( inputFile!=null ) {
+ is = new FileInputStream(inputFile);
+ }
+ Reader r;
+ if ( encoding!=null ) {
+ r = new InputStreamReader(is, encoding);
+ }
+ else {
+ r = new InputStreamReader(is);
+ }
+
+ if ( inputFiles.size()>1 ) {
+ System.err.println(inputFile);
+ }
+ process(lexer, parserClass, parser, is, r);
+ }
+ }
+
+ protected void process(Lexer lexer, Class<? extends Parser> parserClass, Parser parser, InputStream is, Reader r) throws IOException, IllegalAccessException, InvocationTargetException, PrintException {
+ try {
+ ANTLRInputStream input = new ANTLRInputStream(r);
+ lexer.setInputStream(input);
+ CommonTokenStream tokens = new CommonTokenStream(lexer);
+
+ tokens.fill();
+
+ if ( showTokens ) {
+ for (Object tok : tokens.getTokens()) {
+ System.out.println(tok);
+ }
+ }
+
+ if ( startRuleName.equals(LEXER_START_RULE_NAME) ) return;
+
+ if ( diagnostics ) {
+ parser.addErrorListener(new DiagnosticErrorListener());
+ parser.getInterpreter().setPredictionMode(PredictionMode.LL_EXACT_AMBIG_DETECTION);
+ }
+
+ if ( printTree || gui || psFile!=null ) {
+ parser.setBuildParseTree(true);
+ }
+
+ if ( SLL ) { // overrides diagnostics
+ parser.getInterpreter().setPredictionMode(PredictionMode.SLL);
+ }
+
+ parser.setTokenStream(tokens);
+ parser.setTrace(trace);
+
+ try {
+ Method startRule = parserClass.getMethod(startRuleName);
+ ParserRuleContext tree = (ParserRuleContext)startRule.invoke(parser, (Object[])null);
+
+ if ( printTree ) {
+ System.out.println(tree.toStringTree(parser));
+ }
+ if ( gui ) {
+ Trees.inspect(tree, parser);
+ }
+ if ( psFile!=null ) {
+ Trees.save(tree, parser, psFile); // Generate postscript
+ }
+ }
+ catch (NoSuchMethodException nsme) {
+ System.err.println("No method for rule "+startRuleName+" or it has arguments");
+ }
+ }
+ finally {
+ if ( r!=null ) r.close();
+ if ( is!=null ) is.close();
+ }
+ }
+}
diff --git a/tool/src/org/antlr/v4/gui/TreeLayoutAdaptor.java b/tool/src/org/antlr/v4/gui/TreeLayoutAdaptor.java
new file mode 100644
index 0000000..6024e3b
--- /dev/null
+++ b/tool/src/org/antlr/v4/gui/TreeLayoutAdaptor.java
@@ -0,0 +1,149 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.gui;
+
+import org.abego.treelayout.TreeForTreeLayout;
+import org.antlr.v4.runtime.tree.Tree;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+/** Adaptor ANTLR trees to {@link TreeForTreeLayout}. */
+public class TreeLayoutAdaptor implements TreeForTreeLayout<Tree> {
+ private static class AntlrTreeChildrenIterable implements Iterable<Tree> {
+ private final Tree tree;
+
+ public AntlrTreeChildrenIterable(Tree tree) {
+ this.tree = tree;
+ }
+
+ @Override
+ public Iterator<Tree> iterator() {
+ return new Iterator<Tree>() {
+ private int i = 0;
+
+ @Override
+ public boolean hasNext() {
+ return tree.getChildCount() > i;
+ }
+
+ @Override
+ public Tree next() {
+ if (!hasNext())
+ throw new NoSuchElementException();
+
+ return tree.getChild(i++);
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+ }
+
+ private static class AntlrTreeChildrenReverseIterable implements
+ Iterable<Tree>
+ {
+ private final Tree tree;
+
+ public AntlrTreeChildrenReverseIterable(Tree tree) {
+ this.tree = tree;
+ }
+
+ @Override
+ public Iterator<Tree> iterator() {
+ return new Iterator<Tree>() {
+ private int i = tree.getChildCount();
+
+ @Override
+ public boolean hasNext() {
+ return i > 0;
+ }
+
+ @Override
+ public Tree next() {
+ if (!hasNext())
+ throw new NoSuchElementException();
+
+ return tree.getChild(--i);
+ }
+
+ @Override
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+ }
+
+ private Tree root;
+
+ public TreeLayoutAdaptor(Tree root) {
+ this.root = root;
+ }
+
+ @Override
+ public boolean isLeaf(Tree node) {
+ return node.getChildCount() == 0;
+ }
+
+ @Override
+ public boolean isChildOfParent(Tree node, Tree parentNode) {
+ return node.getParent() == parentNode;
+ }
+
+ @Override
+ public Tree getRoot() {
+ return root;
+ }
+
+ @Override
+ public Tree getLastChild(Tree parentNode) {
+ return parentNode.getChild(parentNode.getChildCount() - 1);
+ }
+
+ @Override
+ public Tree getFirstChild(Tree parentNode) {
+ return parentNode.getChild(0);
+ }
+
+ @Override
+ public Iterable<Tree> getChildrenReverse(Tree node) {
+ return new AntlrTreeChildrenReverseIterable(node);
+ }
+
+ @Override
+ public Iterable<Tree> getChildren(Tree node) {
+ return new AntlrTreeChildrenIterable(node);
+ }
+}
diff --git a/tool/src/org/antlr/v4/gui/TreePostScriptGenerator.java b/tool/src/org/antlr/v4/gui/TreePostScriptGenerator.java
new file mode 100644
index 0000000..d78a1c8
--- /dev/null
+++ b/tool/src/org/antlr/v4/gui/TreePostScriptGenerator.java
@@ -0,0 +1,176 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.gui;
+
+import org.abego.treelayout.Configuration;
+import org.abego.treelayout.NodeExtentProvider;
+import org.abego.treelayout.TreeForTreeLayout;
+import org.abego.treelayout.TreeLayout;
+import org.abego.treelayout.util.DefaultConfiguration;
+import org.antlr.v4.runtime.misc.Utils;
+import org.antlr.v4.runtime.tree.ErrorNode;
+import org.antlr.v4.runtime.tree.Tree;
+
+import java.awt.*;
+import java.awt.geom.Rectangle2D;
+import java.util.List;
+
+public class TreePostScriptGenerator {
+ public class VariableExtentProvide implements NodeExtentProvider<Tree> {
+ @Override
+ public double getWidth(Tree tree) {
+ String s = getText(tree);
+ return doc.getWidth(s) + nodeWidthPadding*2;
+ }
+
+ @Override
+ public double getHeight(Tree tree) {
+ String s = getText(tree);
+ double h =
+ doc.getLineHeight() + nodeHeightPaddingAbove + nodeHeightPaddingBelow;
+ String[] lines = s.split("\n");
+ return h * lines.length;
+ }
+ }
+
+ protected double gapBetweenLevels = 17;
+ protected double gapBetweenNodes = 7;
+ protected int nodeWidthPadding = 1; // added to left/right
+ protected int nodeHeightPaddingAbove = 0;
+ protected int nodeHeightPaddingBelow = 5;
+
+ protected Tree root;
+ protected TreeTextProvider treeTextProvider;
+ protected TreeLayout<Tree> treeLayout;
+
+ protected PostScriptDocument doc;
+
+ public TreePostScriptGenerator(List<String> ruleNames, Tree root) {
+ this(ruleNames, root, PostScriptDocument.DEFAULT_FONT, 11);
+ }
+
+ public TreePostScriptGenerator(List<String> ruleNames, Tree root,
+ String fontName, int fontSize)
+ {
+ this.root = root;
+ setTreeTextProvider(new TreeViewer.DefaultTreeTextProvider(ruleNames));
+ doc = new PostScriptDocument(fontName, fontSize);
+ boolean compareNodeIdentities = true;
+ this.treeLayout =
+ new TreeLayout<Tree>(getTreeLayoutAdaptor(root),
+ new VariableExtentProvide(),
+ new DefaultConfiguration<Tree>(gapBetweenLevels,
+ gapBetweenNodes,
+ Configuration.Location.Bottom),
+ compareNodeIdentities);
+ }
+
+ /** Get an adaptor for root that indicates how to walk ANTLR trees.
+ * Override to change the adapter from the default of {@link TreeLayoutAdaptor} */
+ public TreeForTreeLayout<Tree> getTreeLayoutAdaptor(Tree root) {
+ return new TreeLayoutAdaptor(root);
+ }
+
+ public String getPS() {
+ // generate the edges and boxes (with text)
+ generateEdges(getTree().getRoot());
+ for (Tree node : treeLayout.getNodeBounds().keySet()) {
+ generateNode(node);
+ }
+
+ Dimension size = treeLayout.getBounds().getBounds().getSize();
+ doc.boundingBox(size.width, size.height);
+ doc.close();
+ return doc.getPS();
+ }
+
+ protected void generateEdges(Tree parent) {
+ if (!getTree().isLeaf(parent)) {
+ Rectangle2D.Double parentBounds = getBoundsOfNode(parent);
+// System.out.println("%% parent("+getText(parent)+")="+parentBounds);
+ double x1 = parentBounds.getCenterX();
+ double y1 = parentBounds.y;
+ for (Tree child : getChildren(parent)) {
+ Rectangle2D.Double childBounds = getBoundsOfNode(child);
+// System.out.println("%% child("+getText(child)+")="+childBounds);
+ double x2 = childBounds.getCenterX();
+ double y2 = childBounds.getMaxY();
+ doc.line(x1, y1, x2, y2);
+ generateEdges(child);
+ }
+ }
+ }
+
+ protected void generateNode(Tree t) {
+ // draw the text on top of the box (possibly multiple lines)
+ String[] lines = getText(t).split("\n");
+ Rectangle2D.Double box = getBoundsOfNode(t);
+ // for debugging, turn this on to see boundingbox of nodes
+ //doc.rect(box.x, box.y, box.width, box.height);
+ // make error nodes from parse tree red by default
+ if ( t instanceof ErrorNode ) {
+ doc.highlight(box.x, box.y, box.width, box.height);
+ }
+ double x = box.x+nodeWidthPadding;
+ double y = box.y+nodeHeightPaddingBelow;
+ for (int i = 0; i < lines.length; i++) {
+ doc.text(lines[i], x, y);
+ y += doc.getLineHeight();
+ }
+ }
+
+ protected TreeForTreeLayout<Tree> getTree() {
+ return treeLayout.getTree();
+ }
+
+ protected Iterable<Tree> getChildren(Tree parent) {
+ return getTree().getChildren(parent);
+ }
+
+ protected Rectangle2D.Double getBoundsOfNode(Tree node) {
+ return treeLayout.getNodeBounds().get(node);
+ }
+
+ protected String getText(Tree tree) {
+ String s = treeTextProvider.getText(tree);
+ s = Utils.escapeWhitespace(s, false);
+ return s;
+ }
+
+ public TreeTextProvider getTreeTextProvider() {
+ return treeTextProvider;
+ }
+
+ public void setTreeTextProvider(TreeTextProvider treeTextProvider) {
+ this.treeTextProvider = treeTextProvider;
+ }
+
+}
diff --git a/tool/src/org/antlr/v4/gui/TreeTextProvider.java b/tool/src/org/antlr/v4/gui/TreeTextProvider.java
new file mode 100644
index 0000000..9a88fc0
--- /dev/null
+++ b/tool/src/org/antlr/v4/gui/TreeTextProvider.java
@@ -0,0 +1,37 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.gui;
+
+import org.antlr.v4.runtime.tree.Tree;
+
+public interface TreeTextProvider {
+ String getText(Tree node);
+}
diff --git a/tool/src/org/antlr/v4/gui/TreeViewer.java b/tool/src/org/antlr/v4/gui/TreeViewer.java
new file mode 100644
index 0000000..0ca15f3
--- /dev/null
+++ b/tool/src/org/antlr/v4/gui/TreeViewer.java
@@ -0,0 +1,764 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.gui;
+
+import org.abego.treelayout.NodeExtentProvider;
+import org.abego.treelayout.TreeForTreeLayout;
+import org.abego.treelayout.TreeLayout;
+import org.abego.treelayout.util.DefaultConfiguration;
+import org.antlr.v4.runtime.ParserRuleContext;
+import org.antlr.v4.runtime.misc.Utils;
+import org.antlr.v4.runtime.tree.ErrorNode;
+import org.antlr.v4.runtime.tree.Tree;
+import org.antlr.v4.runtime.tree.Trees;
+
+import javax.imageio.ImageIO;
+import javax.print.PrintException;
+import javax.swing.*;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.event.TreeSelectionEvent;
+import javax.swing.event.TreeSelectionListener;
+import javax.swing.filechooser.FileFilter;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.TreePath;
+import javax.swing.tree.TreeSelectionModel;
+import java.awt.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.awt.event.WindowListener;
+import java.awt.geom.CubicCurve2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.prefs.Preferences;
+
+public class TreeViewer extends JComponent {
+ public static final Color LIGHT_RED = new Color(244, 213, 211);
+
+ public static class DefaultTreeTextProvider implements TreeTextProvider {
+ private final List<String> ruleNames;
+
+ public DefaultTreeTextProvider(List<String> ruleNames) {
+ this.ruleNames = ruleNames;
+ }
+
+ @Override
+ public String getText(Tree node) {
+ return String.valueOf(Trees.getNodeText(node, ruleNames));
+ }
+ }
+
+ public static class VariableExtentProvide implements NodeExtentProvider<Tree> {
+ TreeViewer viewer;
+ public VariableExtentProvide(TreeViewer viewer) {
+ this.viewer = viewer;
+ }
+ @Override
+ public double getWidth(Tree tree) {
+ FontMetrics fontMetrics = viewer.getFontMetrics(viewer.font);
+ String s = viewer.getText(tree);
+ int w = fontMetrics.stringWidth(s) + viewer.nodeWidthPadding*2;
+ return w;
+ }
+
+ @Override
+ public double getHeight(Tree tree) {
+ FontMetrics fontMetrics = viewer.getFontMetrics(viewer.font);
+ int h = fontMetrics.getHeight() + viewer.nodeHeightPadding*2;
+ String s = viewer.getText(tree);
+ String[] lines = s.split("\n");
+ return h * lines.length;
+ }
+ }
+
+ protected TreeTextProvider treeTextProvider;
+ protected TreeLayout<Tree> treeLayout;
+ protected java.util.List<Tree> highlightedNodes;
+
+ protected String fontName = "Helvetica"; //Font.SANS_SERIF;
+ protected int fontStyle = Font.PLAIN;
+ protected int fontSize = 11;
+ protected Font font = new Font(fontName, fontStyle, fontSize);
+
+ protected double gapBetweenLevels = 17;
+ protected double gapBetweenNodes = 7;
+ protected int nodeWidthPadding = 2; // added to left/right
+ protected int nodeHeightPadding = 0; // added above/below
+ protected int arcSize = 0; // make an arc in node outline?
+
+ protected double scale = 1.0;
+
+ protected Color boxColor = null; // set to a color to make it draw background
+
+ protected Color highlightedBoxColor = Color.lightGray;
+ protected Color borderColor = null;
+ protected Color textColor = Color.black;
+
+ public TreeViewer(List<String> ruleNames, Tree tree) {
+ setRuleNames(ruleNames);
+ if ( tree!=null ) {
+ setTree(tree);
+ }
+ setFont(font);
+ }
+
+ private void updatePreferredSize() {
+ setPreferredSize(getScaledTreeSize());
+ invalidate();
+ if (getParent() != null) {
+ getParent().validate();
+ }
+ repaint();
+ }
+
+ // ---------------- PAINT -----------------------------------------------
+
+ private boolean useCurvedEdges = false;
+
+ public boolean getUseCurvedEdges() {
+ return useCurvedEdges;
+ }
+
+ public void setUseCurvedEdges(boolean useCurvedEdges) {
+ this.useCurvedEdges = useCurvedEdges;
+ }
+
+ protected void paintEdges(Graphics g, Tree parent) {
+ if (!getTree().isLeaf(parent)) {
+ BasicStroke stroke = new BasicStroke(1.0f, BasicStroke.CAP_ROUND,
+ BasicStroke.JOIN_ROUND);
+ ((Graphics2D)g).setStroke(stroke);
+
+ Rectangle2D.Double parentBounds = getBoundsOfNode(parent);
+ double x1 = parentBounds.getCenterX();
+ double y1 = parentBounds.getMaxY();
+ for (Tree child : getTree().getChildren(parent)) {
+ Rectangle2D.Double childBounds = getBoundsOfNode(child);
+ double x2 = childBounds.getCenterX();
+ double y2 = childBounds.getMinY();
+ if (getUseCurvedEdges()) {
+ CubicCurve2D c = new CubicCurve2D.Double();
+ double ctrlx1 = x1;
+ double ctrly1 = (y1+y2)/2;
+ double ctrlx2 = x2;
+ double ctrly2 = y1;
+ c.setCurve(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2);
+ ((Graphics2D) g).draw(c);
+ } else {
+ g.drawLine((int) x1, (int) y1,
+ (int) x2, (int) y2);
+ }
+ paintEdges(g, child);
+ }
+ }
+ }
+
+ protected void paintBox(Graphics g, Tree tree) {
+ Rectangle2D.Double box = getBoundsOfNode(tree);
+ // draw the box in the background
+ boolean ruleFailedAndMatchedNothing = false;
+ if ( tree instanceof ParserRuleContext ) {
+ ParserRuleContext ctx = (ParserRuleContext) tree;
+ ruleFailedAndMatchedNothing = ctx.exception != null &&
+ ctx.stop != null && ctx.stop.getTokenIndex() < ctx.start.getTokenIndex();
+ }
+ if ( isHighlighted(tree) || boxColor!=null ||
+ tree instanceof ErrorNode ||
+ ruleFailedAndMatchedNothing)
+ {
+ if ( isHighlighted(tree) ) g.setColor(highlightedBoxColor);
+ else if ( tree instanceof ErrorNode || ruleFailedAndMatchedNothing ) g.setColor(LIGHT_RED);
+ else g.setColor(boxColor);
+ g.fillRoundRect((int) box.x, (int) box.y, (int) box.width - 1,
+ (int) box.height - 1, arcSize, arcSize);
+ }
+ if ( borderColor!=null ) {
+ g.setColor(borderColor);
+ g.drawRoundRect((int) box.x, (int) box.y, (int) box.width - 1,
+ (int) box.height - 1, arcSize, arcSize);
+ }
+
+ // draw the text on top of the box (possibly multiple lines)
+ g.setColor(textColor);
+ String s = getText(tree);
+ String[] lines = s.split("\n");
+ FontMetrics m = getFontMetrics(font);
+ int x = (int) box.x + arcSize / 2 + nodeWidthPadding;
+ int y = (int) box.y + m.getAscent() + m.getLeading() + 1 + nodeHeightPadding;
+ for (int i = 0; i < lines.length; i++) {
+ text(g, lines[i], x, y);
+ y += m.getHeight();
+ }
+ }
+
+ public void text(Graphics g, String s, int x, int y) {
+// System.out.println("drawing '"+s+"' @ "+x+","+y);
+ s = Utils.escapeWhitespace(s, true);
+ g.drawString(s, x, y);
+ }
+
+ @Override
+ public void paint(Graphics g) {
+ super.paint(g);
+
+ if ( treeLayout==null ) {
+ return;
+ }
+
+ Graphics2D g2 = (Graphics2D)g;
+ // anti-alias the lines
+ g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+ RenderingHints.VALUE_ANTIALIAS_ON);
+
+ // Anti-alias the text
+ g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
+ RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+
+// AffineTransform at = g2.getTransform();
+// g2.scale(
+// (double) this.getWidth() / 400,
+// (double) this.getHeight() / 400);
+//
+// g2.setTransform(at);
+
+ paintEdges(g, getTree().getRoot());
+
+ // paint the boxes
+ for (Tree Tree : treeLayout.getNodeBounds().keySet()) {
+ paintBox(g, Tree);
+ }
+ }
+
+ @Override
+ protected Graphics getComponentGraphics(Graphics g) {
+ Graphics2D g2d=(Graphics2D)g;
+ g2d.scale(scale, scale);
+ return super.getComponentGraphics(g2d);
+ }
+
+ // ----------------------------------------------------------------------
+
+
+ private static final String DIALOG_WIDTH_PREFS_KEY = "dialog_width";
+ private static final String DIALOG_HEIGHT_PREFS_KEY = "dialog_height";
+ private static final String DIALOG_X_PREFS_KEY = "dialog_x";
+ private static final String DIALOG_Y_PREFS_KEY = "dialog_y";
+ private static final String DIALOG_DIVIDER_LOC_PREFS_KEY = "dialog_divider_location";
+ private static final String DIALOG_VIEWER_SCALE_PREFS_KEY = "dialog_viewer_scale";
+
+ protected static JDialog showInDialog(final TreeViewer viewer) {
+ final JDialog dialog = new JDialog();
+ dialog.setTitle("Parse Tree Inspector");
+
+ final Preferences prefs = Preferences.userNodeForPackage(TreeViewer.class);
+
+ // Make new content panes
+ final Container mainPane = new JPanel(new BorderLayout(5,5));
+ final Container contentPane = new JPanel(new BorderLayout(0,0));
+ contentPane.setBackground(Color.white);
+
+ // Wrap viewer in scroll pane
+ JScrollPane scrollPane = new JScrollPane(viewer);
+ // Make the scrollpane (containing the viewer) the center component
+ contentPane.add(scrollPane, BorderLayout.CENTER);
+
+ JPanel wrapper = new JPanel(new FlowLayout());
+
+ // Add button to bottom
+ JPanel bottomPanel = new JPanel(new BorderLayout(0,0));
+ contentPane.add(bottomPanel, BorderLayout.SOUTH);
+
+ JButton ok = new JButton("OK");
+ ok.addActionListener(
+ new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ dialog.dispatchEvent(new WindowEvent(dialog, WindowEvent.WINDOW_CLOSING));
+ }
+ }
+ );
+ wrapper.add(ok);
+
+ // Add an export-to-png button right of the "OK" button
+ JButton png = new JButton("Export as PNG");
+ png.addActionListener(
+ new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ generatePNGFile(viewer, dialog);
+ }
+ }
+ );
+ wrapper.add(png);
+
+ bottomPanel.add(wrapper, BorderLayout.SOUTH);
+
+ // Add scale slider
+ double lastKnownViewerScale = prefs.getDouble(DIALOG_VIEWER_SCALE_PREFS_KEY, viewer.getScale());
+ viewer.setScale(lastKnownViewerScale);
+
+ int sliderValue = (int) ((lastKnownViewerScale - 1.0) * 1000);
+ final JSlider scaleSlider = new JSlider(JSlider.HORIZONTAL, -999, 1000, sliderValue);
+
+ scaleSlider.addChangeListener(
+ new ChangeListener() {
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ int v = scaleSlider.getValue();
+ viewer.setScale(v / 1000.0 + 1.0);
+ }
+ }
+ );
+ bottomPanel.add(scaleSlider, BorderLayout.CENTER);
+
+ // Add a JTree representing the parser tree of the input.
+ JPanel treePanel = new JPanel(new BorderLayout(5, 5));
+
+ // An "empty" icon that will be used for the JTree's nodes.
+ Icon empty = new EmptyIcon();
+
+ UIManager.put("Tree.closedIcon", empty);
+ UIManager.put("Tree.openIcon", empty);
+ UIManager.put("Tree.leafIcon", empty);
+
+ Tree parseTreeRoot = viewer.getTree().getRoot();
+ TreeNodeWrapper nodeRoot = new TreeNodeWrapper(parseTreeRoot, viewer);
+ fillTree(nodeRoot, parseTreeRoot, viewer);
+ final JTree tree = new JTree(nodeRoot);
+ tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
+
+ tree.addTreeSelectionListener(new TreeSelectionListener() {
+ @Override
+ public void valueChanged(TreeSelectionEvent e) {
+
+ JTree selectedTree = (JTree) e.getSource();
+ TreePath path = selectedTree.getSelectionPath();
+ TreeNodeWrapper treeNode = (TreeNodeWrapper) path.getLastPathComponent();
+
+ // Set the clicked AST.
+ viewer.setTree((Tree) treeNode.getUserObject());
+ }
+ });
+
+ treePanel.add(new JScrollPane(tree));
+
+ // Create the pane for both the JTree and the AST
+ final JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
+ treePanel, contentPane);
+
+ mainPane.add(splitPane, BorderLayout.CENTER);
+
+ dialog.setContentPane(mainPane);
+
+ // make viz
+ WindowListener exitListener = new WindowAdapter() {
+ public void windowClosing(WindowEvent e) {
+ prefs.putInt(DIALOG_WIDTH_PREFS_KEY, (int) dialog.getSize().getWidth());
+ prefs.putInt(DIALOG_HEIGHT_PREFS_KEY, (int) dialog.getSize().getHeight());
+ prefs.putDouble(DIALOG_X_PREFS_KEY, dialog.getLocationOnScreen().getX());
+ prefs.putDouble(DIALOG_Y_PREFS_KEY, dialog.getLocationOnScreen().getY());
+ prefs.putInt(DIALOG_DIVIDER_LOC_PREFS_KEY, splitPane.getDividerLocation());
+ prefs.putDouble(DIALOG_VIEWER_SCALE_PREFS_KEY, viewer.getScale());
+
+ dialog.setVisible(false);
+ dialog.dispose();
+ }
+ };
+ dialog.addWindowListener(exitListener);
+ dialog.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+
+ int width = prefs.getInt(DIALOG_WIDTH_PREFS_KEY, 600);
+ int height = prefs.getInt(DIALOG_HEIGHT_PREFS_KEY, 500);
+ dialog.setPreferredSize(new Dimension(width, height));
+ dialog.pack();
+
+ // After pack(): set the divider at 1/3 (200/600) of the frame.
+ int dividerLocation = prefs.getInt(DIALOG_DIVIDER_LOC_PREFS_KEY, 200);
+ splitPane.setDividerLocation(dividerLocation);
+
+ if (prefs.getDouble(DIALOG_X_PREFS_KEY, -1) != -1) {
+ dialog.setLocation(
+ (int)prefs.getDouble(DIALOG_X_PREFS_KEY, 100),
+ (int)prefs.getDouble(DIALOG_Y_PREFS_KEY, 100)
+ );
+ }
+ else {
+ dialog.setLocationRelativeTo(null);
+ }
+
+ dialog.setVisible(true);
+ return dialog;
+ }
+
+ private static void generatePNGFile(TreeViewer viewer, JDialog dialog) {
+ BufferedImage bi = new BufferedImage(viewer.getSize().width,
+ viewer.getSize().height,
+ BufferedImage.TYPE_INT_ARGB);
+ Graphics g = bi.createGraphics();
+ viewer.paint(g);
+ g.dispose();
+
+ try {
+ File suggestedFile = generateNonExistingPngFile();
+ JFileChooser fileChooser = new JFileChooserConfirmOverwrite();
+ fileChooser.setCurrentDirectory(suggestedFile.getParentFile());
+ fileChooser.setSelectedFile(suggestedFile);
+ FileFilter pngFilter = new FileFilter() {
+
+ @Override
+ public boolean accept(File pathname) {
+ if (pathname.isFile()) {
+ return pathname.getName().toLowerCase().endsWith(".png");
+ }
+
+ return true;
+ }
+
+ @Override
+ public String getDescription() {
+ return "PNG Files (*.png)";
+ }
+ };
+
+ fileChooser.addChoosableFileFilter(pngFilter);
+ fileChooser.setFileFilter(pngFilter);
+
+ int returnValue = fileChooser.showSaveDialog(dialog);
+ if (returnValue == JFileChooser.APPROVE_OPTION) {
+ File pngFile = fileChooser.getSelectedFile();
+ ImageIO.write(bi, "png", pngFile);
+
+ try {
+ // Try to open the parent folder using the OS' native file manager.
+ Desktop.getDesktop().open(pngFile.getParentFile());
+ }
+ catch (Exception ex) {
+ // We could not launch the file manager: just show a popup that we
+ // succeeded in saving the PNG file.
+ JOptionPane.showMessageDialog(dialog, "Saved PNG to: " +
+ pngFile.getAbsolutePath());
+ ex.printStackTrace();
+ }
+ }
+ }
+ catch (Exception ex) {
+ JOptionPane.showMessageDialog(dialog,
+ "Could not export to PNG: " + ex.getMessage(),
+ "Error",
+ JOptionPane.ERROR_MESSAGE);
+ ex.printStackTrace();
+ }
+ }
+
+ private static File generateNonExistingPngFile() {
+
+ final String parent = ".";
+ final String name = "antlr4_parse_tree";
+ final String extension = ".png";
+
+ File pngFile = new File(parent, name + extension);
+
+ int counter = 1;
+
+ // Keep looping until we create a File that does not yet exist.
+ while (pngFile.exists()) {
+ pngFile = new File(parent, name + "_"+ counter + extension);
+ counter++;
+ }
+
+ return pngFile;
+ }
+
+ private static void fillTree(TreeNodeWrapper node, Tree tree, TreeViewer viewer) {
+
+ if (tree == null) {
+ return;
+ }
+
+ for (int i = 0; i < tree.getChildCount(); i++) {
+
+ Tree childTree = tree.getChild(i);
+ TreeNodeWrapper childNode = new TreeNodeWrapper(childTree, viewer);
+
+ node.add(childNode);
+
+ fillTree(childNode, childTree, viewer);
+ }
+ }
+
+ private Dimension getScaledTreeSize() {
+ Dimension scaledTreeSize =
+ treeLayout.getBounds().getBounds().getSize();
+ scaledTreeSize = new Dimension((int)(scaledTreeSize.width*scale),
+ (int)(scaledTreeSize.height*scale));
+ return scaledTreeSize;
+ }
+
+
+ public Future<JDialog> open() {
+ final TreeViewer viewer = this;
+ viewer.setScale(1.5);
+ Callable<JDialog> callable = new Callable<JDialog>() {
+ JDialog result;
+
+ @Override
+ public JDialog call() throws Exception {
+ SwingUtilities.invokeAndWait(new Runnable() {
+ @Override
+ public void run() {
+ result = showInDialog(viewer);
+ }
+ });
+
+ return result;
+ }
+ };
+
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+
+ try {
+ return executor.submit(callable);
+ }
+ finally {
+ executor.shutdown();
+ }
+ }
+
+ public void save(String fileName) throws IOException, PrintException {
+ JDialog dialog = new JDialog();
+ Container contentPane = dialog.getContentPane();
+ ((JComponent) contentPane).setBorder(BorderFactory.createEmptyBorder(
+ 10, 10, 10, 10));
+ contentPane.add(this);
+ contentPane.setBackground(Color.white);
+ dialog.pack();
+ dialog.setLocationRelativeTo(null);
+ dialog.dispose();
+ GraphicsSupport.saveImage(this, fileName);
+ }
+
+ // ---------------------------------------------------
+
+ protected Rectangle2D.Double getBoundsOfNode(Tree node) {
+ return treeLayout.getNodeBounds().get(node);
+ }
+
+ protected String getText(Tree tree) {
+ String s = treeTextProvider.getText(tree);
+ s = Utils.escapeWhitespace(s, true);
+ return s;
+ }
+
+ public TreeTextProvider getTreeTextProvider() {
+ return treeTextProvider;
+ }
+
+ public void setTreeTextProvider(TreeTextProvider treeTextProvider) {
+ this.treeTextProvider = treeTextProvider;
+ }
+
+ public void setFontSize(int sz) {
+ fontSize = sz;
+ font = new Font(fontName, fontStyle, fontSize);
+ }
+
+ public void setFontName(String name) {
+ fontName = name;
+ font = new Font(fontName, fontStyle, fontSize);
+ }
+
+ /** Slow for big lists of highlighted nodes */
+ public void addHighlightedNodes(Collection<Tree> nodes) {
+ highlightedNodes = new ArrayList<Tree>();
+ highlightedNodes.addAll(nodes);
+ }
+
+ public void removeHighlightedNodes(Collection<Tree> nodes) {
+ if ( highlightedNodes!=null ) {
+ // only remove exact objects defined by ==, not equals()
+ for (Tree t : nodes) {
+ int i = getHighlightedNodeIndex(t);
+ if ( i>=0 ) highlightedNodes.remove(i);
+ }
+ }
+ }
+
+ protected boolean isHighlighted(Tree node) {
+ return getHighlightedNodeIndex(node) >= 0;
+ }
+
+ protected int getHighlightedNodeIndex(Tree node) {
+ if ( highlightedNodes==null ) return -1;
+ for (int i = 0; i < highlightedNodes.size(); i++) {
+ Tree t = highlightedNodes.get(i);
+ if ( t == node ) return i;
+ }
+ return -1;
+ }
+
+ @Override
+ public Font getFont() {
+ return font;
+ }
+
+ @Override
+ public void setFont(Font font) {
+ this.font = font;
+ }
+
+ public int getArcSize() {
+ return arcSize;
+ }
+
+ public void setArcSize(int arcSize) {
+ this.arcSize = arcSize;
+ }
+
+ public Color getBoxColor() {
+ return boxColor;
+ }
+
+ public void setBoxColor(Color boxColor) {
+ this.boxColor = boxColor;
+ }
+
+ public Color getHighlightedBoxColor() {
+ return highlightedBoxColor;
+ }
+
+ public void setHighlightedBoxColor(Color highlightedBoxColor) {
+ this.highlightedBoxColor = highlightedBoxColor;
+ }
+
+ public Color getBorderColor() {
+ return borderColor;
+ }
+
+ public void setBorderColor(Color borderColor) {
+ this.borderColor = borderColor;
+ }
+
+ public Color getTextColor() {
+ return textColor;
+ }
+
+ public void setTextColor(Color textColor) {
+ this.textColor = textColor;
+ }
+
+ protected TreeForTreeLayout<Tree> getTree() {
+ return treeLayout.getTree();
+ }
+
+ public void setTree(Tree root) {
+ if ( root!=null ) {
+ boolean useIdentity = true; // compare node identity
+ this.treeLayout =
+ new TreeLayout<Tree>(getTreeLayoutAdaptor(root),
+ new TreeViewer.VariableExtentProvide(this),
+ new DefaultConfiguration<Tree>(gapBetweenLevels,
+ gapBetweenNodes),
+ useIdentity);
+ // Let the UI display this new AST.
+ updatePreferredSize();
+ }
+ else {
+ this.treeLayout = null;
+ repaint();
+ }
+ }
+
+ /** Get an adaptor for root that indicates how to walk ANTLR trees.
+ * Override to change the adapter from the default of {@link TreeLayoutAdaptor} */
+ public TreeForTreeLayout<Tree> getTreeLayoutAdaptor(Tree root) {
+ return new TreeLayoutAdaptor(root);
+ }
+
+ public double getScale() {
+ return scale;
+ }
+
+ public void setScale(double scale) {
+ if(scale <= 0) {
+ scale = 1;
+ }
+ this.scale = scale;
+ updatePreferredSize();
+ }
+
+ public void setRuleNames(List<String> ruleNames) {
+ setTreeTextProvider(new DefaultTreeTextProvider(ruleNames));
+ }
+
+ private static class TreeNodeWrapper extends DefaultMutableTreeNode {
+
+ final TreeViewer viewer;
+
+ TreeNodeWrapper(Tree tree, TreeViewer viewer) {
+ super(tree);
+ this.viewer = viewer;
+ }
+
+ @Override
+ public String toString() {
+ return viewer.getText((Tree) this.getUserObject());
+ }
+ }
+
+ private static class EmptyIcon implements Icon {
+
+ @Override
+ public int getIconWidth() {
+ return 0;
+ }
+
+ @Override
+ public int getIconHeight() {
+ return 0;
+ }
+
+ @Override
+ public void paintIcon(Component c, Graphics g, int x, int y) {
+ /* Do nothing. */
+ }
+ }
+}
diff --git a/tool/src/org/antlr/v4/gui/Trees.java b/tool/src/org/antlr/v4/gui/Trees.java
new file mode 100644
index 0000000..53796ab
--- /dev/null
+++ b/tool/src/org/antlr/v4/gui/Trees.java
@@ -0,0 +1,120 @@
+package org.antlr.v4.gui;
+
+import org.antlr.v4.runtime.Parser;
+import org.antlr.v4.runtime.misc.Utils;
+import org.antlr.v4.runtime.tree.Tree;
+
+import javax.print.PrintException;
+import javax.swing.*;
+import java.io.BufferedWriter;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.Future;
+
+public class Trees {
+ /** Call this method to view a parse tree in a dialog box visually. */
+ public static Future<JDialog> inspect(Tree t, List<String> ruleNames) {
+ TreeViewer viewer = new TreeViewer(ruleNames, t);
+ return viewer.open();
+ }
+
+ /** Call this method to view a parse tree in a dialog box visually. */
+ public static Future<JDialog> inspect(Tree t, Parser parser) {
+ List<String> ruleNames = parser != null ? Arrays.asList(parser.getRuleNames()) : null;
+ return inspect(t, ruleNames);
+ }
+
+ /** Save this tree in a postscript file */
+ public static void save(Tree t, Parser parser, String fileName)
+ throws IOException, PrintException
+ {
+ List<String> ruleNames = parser != null ? Arrays.asList(parser.getRuleNames()) : null;
+ save(t, ruleNames, fileName);
+ }
+
+ /** Save this tree in a postscript file using a particular font name and size */
+ public static void save(Tree t, Parser parser, String fileName,
+ String fontName, int fontSize)
+ throws IOException
+ {
+ List<String> ruleNames = parser != null ? Arrays.asList(parser.getRuleNames()) : null;
+ save(t, ruleNames, fileName, fontName, fontSize);
+ }
+
+ /** Save this tree in a postscript file */
+ public static void save(Tree t, List<String> ruleNames, String fileName)
+ throws IOException, PrintException
+ {
+ writePS(t, ruleNames, fileName);
+ }
+
+ /** Save this tree in a postscript file using a particular font name and size */
+ public static void save(Tree t,
+ List<String> ruleNames, String fileName,
+ String fontName, int fontSize)
+ throws IOException
+ {
+ writePS(t, ruleNames, fileName, fontName, fontSize);
+ }
+
+ public static String getPS(Tree t, List<String> ruleNames,
+ String fontName, int fontSize)
+ {
+ TreePostScriptGenerator psgen =
+ new TreePostScriptGenerator(ruleNames, t, fontName, fontSize);
+ return psgen.getPS();
+ }
+
+ public static String getPS(Tree t, List<String> ruleNames) {
+ return getPS(t, ruleNames, "Helvetica", 11);
+ }
+
+ public static void writePS(Tree t, List<String> ruleNames,
+ String fileName,
+ String fontName, int fontSize)
+ throws IOException
+ {
+ String ps = getPS(t, ruleNames, fontName, fontSize);
+ FileWriter f = new FileWriter(fileName);
+ BufferedWriter bw = new BufferedWriter(f);
+ try {
+ bw.write(ps);
+ }
+ finally {
+ bw.close();
+ }
+ }
+
+ public static void writePS(Tree t, List<String> ruleNames, String fileName)
+ throws IOException
+ {
+ writePS(t, ruleNames, fileName, "Helvetica", 11);
+ }
+
+ /** Print out a whole tree in LISP form. Arg nodeTextProvider is used on the
+ * node payloads to get the text for the nodes.
+ *
+ * @since 4.5.1
+ */
+ public static String toStringTree(Tree t, TreeTextProvider nodeTextProvider) {
+ if ( t==null ) return "null";
+ String s = Utils.escapeWhitespace(nodeTextProvider.getText(t), false);
+ if ( t.getChildCount()==0 ) return s;
+ StringBuilder buf = new StringBuilder();
+ buf.append("(");
+ s = Utils.escapeWhitespace(nodeTextProvider.getText(t), false);
+ buf.append(s);
+ buf.append(' ');
+ for (int i = 0; i<t.getChildCount(); i++) {
+ if ( i>0 ) buf.append(' ');
+ buf.append(toStringTree(t.getChild(i), nodeTextProvider));
+ }
+ buf.append(")");
+ return buf.toString();
+ }
+
+ private Trees() {
+ }
+}
diff --git a/tool/src/org/antlr/v4/misc/CharSupport.java b/tool/src/org/antlr/v4/misc/CharSupport.java
new file mode 100644
index 0000000..22e9648
--- /dev/null
+++ b/tool/src/org/antlr/v4/misc/CharSupport.java
@@ -0,0 +1,153 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.misc;
+
+import org.antlr.v4.runtime.Lexer;
+
+/** */
+public class CharSupport {
+ /** When converting ANTLR char and string literals, here is the
+ * value set of escape chars.
+ */
+ public static int ANTLRLiteralEscapedCharValue[] = new int[255];
+
+ /** Given a char, we need to be able to show as an ANTLR literal.
+ */
+ public static String ANTLRLiteralCharValueEscape[] = new String[255];
+
+ static {
+ ANTLRLiteralEscapedCharValue['n'] = '\n';
+ ANTLRLiteralEscapedCharValue['r'] = '\r';
+ ANTLRLiteralEscapedCharValue['t'] = '\t';
+ ANTLRLiteralEscapedCharValue['b'] = '\b';
+ ANTLRLiteralEscapedCharValue['f'] = '\f';
+ ANTLRLiteralEscapedCharValue['\\'] = '\\';
+ ANTLRLiteralEscapedCharValue['\''] = '\'';
+ ANTLRLiteralEscapedCharValue['"'] = '"';
+ ANTLRLiteralCharValueEscape['\n'] = "\\n";
+ ANTLRLiteralCharValueEscape['\r'] = "\\r";
+ ANTLRLiteralCharValueEscape['\t'] = "\\t";
+ ANTLRLiteralCharValueEscape['\b'] = "\\b";
+ ANTLRLiteralCharValueEscape['\f'] = "\\f";
+ ANTLRLiteralCharValueEscape['\\'] = "\\\\";
+ ANTLRLiteralCharValueEscape['\''] = "\\'";
+ }
+
+ /** Return a string representing the escaped char for code c. E.g., If c
+ * has value 0x100, you will get "\u0100". ASCII gets the usual
+ * char (non-hex) representation. Control characters are spit out
+ * as unicode. While this is specially set up for returning Java strings,
+ * it can be used by any language target that has the same syntax. :)
+ */
+ public static String getANTLRCharLiteralForChar(int c) {
+ if ( c< Lexer.MIN_CHAR_VALUE ) {
+ return "'<INVALID>'";
+ }
+ if ( c<ANTLRLiteralCharValueEscape.length && ANTLRLiteralCharValueEscape[c]!=null ) {
+ return '\''+ANTLRLiteralCharValueEscape[c]+'\'';
+ }
+ if ( Character.UnicodeBlock.of((char)c)==Character.UnicodeBlock.BASIC_LATIN &&
+ !Character.isISOControl((char)c) ) {
+ if ( c=='\\' ) {
+ return "'\\\\'";
+ }
+ if ( c=='\'') {
+ return "'\\''";
+ }
+ return '\''+Character.toString((char)c)+'\'';
+ }
+ // turn on the bit above max "\uFFFF" value so that we pad with zeros
+ // then only take last 4 digits
+ String hex = Integer.toHexString(c|0x10000).toUpperCase().substring(1,5);
+ String unicodeStr = "'\\u"+hex+"'";
+ return unicodeStr;
+ }
+
+ /** Given a literal like (the 3 char sequence with single quotes) 'a',
+ * return the int value of 'a'. Convert escape sequences here also.
+ * Return -1 if not single char.
+ */
+ public static int getCharValueFromGrammarCharLiteral(String literal) {
+ if ( literal==null || literal.length()<3 ) return -1;
+ return getCharValueFromCharInGrammarLiteral(literal.substring(1,literal.length()-1));
+ }
+
+ /** Given char x or \t or \u1234 return the char value;
+ * Unnecessary escapes like '\{' yield -1.
+ */
+ public static int getCharValueFromCharInGrammarLiteral(String cstr) {
+ switch ( cstr.length() ) {
+ case 1 :
+ // 'x'
+ return cstr.charAt(0); // no escape char
+ case 2 :
+ if ( cstr.charAt(0)!='\\' ) return -1;
+ // '\x' (antlr lexer will catch invalid char)
+ if ( Character.isDigit(cstr.charAt(1)) ) return -1;
+ int escChar = cstr.charAt(1);
+ int charVal = ANTLRLiteralEscapedCharValue[escChar];
+ if ( charVal==0 ) return -1;
+ return charVal;
+ case 6 :
+ // '\u1234'
+ if ( !cstr.startsWith("\\u") ) return -1;
+ String unicodeChars = cstr.substring(2, cstr.length());
+ return Integer.parseInt(unicodeChars, 16);
+ default :
+ return -1;
+ }
+ }
+
+ public static String getStringFromGrammarStringLiteral(String literal) {
+ StringBuilder buf = new StringBuilder();
+ int i = 1; // skip first quote
+ int n = literal.length()-1; // skip last quote
+ while ( i < n ) { // scan all but last quote
+ int end = i+1;
+ if ( literal.charAt(i) == '\\' ) {
+ end = i+2;
+ if ( (i+1)>=n ) break; // ignore spurious \ on end
+ if ( literal.charAt(i+1) == 'u' ) end = i+6;
+ }
+ if ( end>n ) break;
+ String esc = literal.substring(i, end);
+ int c = getCharValueFromCharInGrammarLiteral(esc);
+ if ( c==-1 ) { buf.append(esc); }
+ else buf.append((char)c);
+ i = end;
+ }
+ return buf.toString();
+ }
+
+ public static String capitalize(String s) {
+ return Character.toUpperCase(s.charAt(0)) + s.substring(1);
+ }
+}
diff --git a/tool/src/org/antlr/v4/misc/FrequencySet.java b/tool/src/org/antlr/v4/misc/FrequencySet.java
new file mode 100644
index 0000000..94e467c
--- /dev/null
+++ b/tool/src/org/antlr/v4/misc/FrequencySet.java
@@ -0,0 +1,52 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.misc;
+
+import java.util.HashMap;
+
+/** Count how many of each key we have; not thread safe */
+public class FrequencySet<T> extends HashMap<T, MutableInt> {
+ public int count(T key) {
+ MutableInt value = get(key);
+ if (value == null) return 0;
+ return value.v;
+ }
+ public void add(T key) {
+ MutableInt value = get(key);
+ if (value == null) {
+ value = new MutableInt(1);
+ put(key, value);
+ }
+ else {
+ value.v++;
+ }
+ }
+}
diff --git a/tool/src/org/antlr/v4/misc/Graph.java b/tool/src/org/antlr/v4/misc/Graph.java
new file mode 100644
index 0000000..2509c81
--- /dev/null
+++ b/tool/src/org/antlr/v4/misc/Graph.java
@@ -0,0 +1,117 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.v4.misc;
+
+import org.antlr.v4.runtime.misc.OrderedHashSet;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/** A generic graph with edges; Each node as a single Object payload.
+ * This is only used to topologically sort a list of file dependencies
+ * at the moment.
+ */
+public class Graph<T> {
+
+ public static class Node<T> {
+ T payload;
+ List<Node<T>> edges; // points at which nodes?
+
+ public Node(T payload) { this.payload = payload; }
+
+ public void addEdge(Node<T> n) {
+ if ( edges==null ) edges = new ArrayList<Node<T>>();
+ if ( !edges.contains(n) ) edges.add(n);
+ }
+
+ @Override
+ public String toString() { return payload.toString(); }
+ }
+
+ /** Map from node payload to node containing it */
+ protected Map<T,Node<T>> nodes = new LinkedHashMap<T,Node<T>>();
+
+ public void addEdge(T a, T b) {
+ //System.out.println("add edge "+a+" to "+b);
+ Node<T> a_node = getNode(a);
+ Node<T> b_node = getNode(b);
+ a_node.addEdge(b_node);
+ }
+
+ protected Node<T> getNode(T a) {
+ Node<T> existing = nodes.get(a);
+ if ( existing!=null ) return existing;
+ Node<T> n = new Node<T>(a);
+ nodes.put(a, n);
+ return n;
+ }
+
+ /** DFS-based topological sort. A valid sort is the reverse of
+ * the post-order DFA traversal. Amazingly simple but true.
+ * For sorting, I'm not following convention here since ANTLR
+ * needs the opposite. Here's what I assume for sorting:
+ *
+ * If there exists an edge u -> v then u depends on v and v
+ * must happen before u.
+ *
+ * So if this gives nonreversed postorder traversal, I get the order
+ * I want.
+ */
+ public List<T> sort() {
+ Set<Node<T>> visited = new OrderedHashSet<Node<T>>();
+ ArrayList<T> sorted = new ArrayList<T>();
+ while ( visited.size() < nodes.size() ) {
+ // pick any unvisited node, n
+ Node<T> n = null;
+ for (Node<T> tNode : nodes.values()) {
+ n = tNode;
+ if ( !visited.contains(n) ) break;
+ }
+ if (n!=null) { // if at least one unvisited
+ DFS(n, visited, sorted);
+ }
+ }
+ return sorted;
+ }
+
+ public void DFS(Node<T> n, Set<Node<T>> visited, ArrayList<T> sorted) {
+ if ( visited.contains(n) ) return;
+ visited.add(n);
+ if ( n.edges!=null ) {
+ for (Node<T> target : n.edges) {
+ DFS(target, visited, sorted);
+ }
+ }
+ sorted.add(n.payload);
+ }
+} \ No newline at end of file
diff --git a/tool/src/org/antlr/v4/misc/MutableInt.java b/tool/src/org/antlr/v4/misc/MutableInt.java
new file mode 100644
index 0000000..816a4ba
--- /dev/null
+++ b/tool/src/org/antlr/v4/misc/MutableInt.java
@@ -0,0 +1,56 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.misc;
+
+public class MutableInt extends Number implements Comparable<Number> {
+ public int v;
+
+ public MutableInt(int v) { this.v = v; }
+
+ @Override
+ public boolean equals(Object o) {
+ if ( o instanceof Number ) return v == ((Number)o).intValue();
+ return false;
+ }
+
+ @Override public int hashCode() { return v; }
+
+ @Override public int compareTo(Number o) { return v-o.intValue(); }
+ @Override public int intValue() { return v; }
+ @Override public long longValue() { return v; }
+ @Override public float floatValue() { return v; }
+ @Override public double doubleValue() { return v; }
+
+ @Override
+ public String toString() {
+ return String.valueOf(v);
+ }
+}
diff --git a/tool/src/org/antlr/v4/misc/OrderedHashMap.java b/tool/src/org/antlr/v4/misc/OrderedHashMap.java
new file mode 100644
index 0000000..ce37b86
--- /dev/null
+++ b/tool/src/org/antlr/v4/misc/OrderedHashMap.java
@@ -0,0 +1,73 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.misc;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/** I need the get-element-i functionality so I'm subclassing
+ * LinkedHashMap.
+ */
+public class OrderedHashMap<K,V> extends LinkedHashMap<K,V> {
+ /** Track the elements as they are added to the set */
+ protected List<K> elements = new ArrayList<K>();
+
+ public K getKey(int i) { return elements.get(i); }
+
+ public V getElement(int i) { return get(elements.get(i)); }
+
+ @Override
+ public V put(K key, V value) {
+ elements.add(key);
+ return super.put(key, value);
+ }
+
+ @Override
+ public void putAll(Map<? extends K, ? extends V> m) {
+ for (Map.Entry<? extends K, ? extends V> entry : m.entrySet()) {
+ put(entry.getKey(), entry.getValue());
+ }
+ }
+
+ @Override
+ public V remove(Object key) {
+ elements.remove(key);
+ return super.remove(key);
+ }
+
+ @Override
+ public void clear() {
+ elements.clear();
+ super.clear();
+ }
+}
diff --git a/tool/src/org/antlr/v4/misc/Utils.java b/tool/src/org/antlr/v4/misc/Utils.java
new file mode 100644
index 0000000..c62003c
--- /dev/null
+++ b/tool/src/org/antlr/v4/misc/Utils.java
@@ -0,0 +1,171 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.misc;
+
+import org.antlr.v4.tool.ast.GrammarAST;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/** */
+public class Utils {
+ public static final int INTEGER_POOL_MAX_VALUE = 1000;
+
+ public interface Filter<T> {
+ boolean select(T t);
+ }
+
+ public interface Func0<TResult> {
+ TResult exec();
+ }
+
+ public interface Func1<T1, TResult> {
+ TResult exec(T1 arg1);
+ }
+
+ static Integer[] ints = new Integer[INTEGER_POOL_MAX_VALUE+1];
+
+ /** Integer objects are immutable so share all Integers with the
+ * same value up to some max size. Use an array as a perfect hash.
+ * Return shared object for 0..INTEGER_POOL_MAX_VALUE or a new
+ * Integer object with x in it. Java's autoboxing only caches up to 127.
+ public static Integer integer(int x) {
+ if ( x<0 || x>INTEGER_POOL_MAX_VALUE ) {
+ return new Integer(x);
+ }
+ if ( ints[x]==null ) {
+ ints[x] = new Integer(x);
+ }
+ return ints[x];
+ }
+ */
+
+ public static String stripFileExtension(String name) {
+ if ( name==null ) return null;
+ int lastDot = name.lastIndexOf('.');
+ if ( lastDot<0 ) return name;
+ return name.substring(0, lastDot);
+ }
+
+ public static String join(Object[] a, String separator) {
+ StringBuilder buf = new StringBuilder();
+ for (int i=0; i<a.length; i++) {
+ Object o = a[i];
+ buf.append(o.toString());
+ if ( (i+1)<a.length ) {
+ buf.append(separator);
+ }
+ }
+ return buf.toString();
+ }
+
+ public static String sortLinesInString(String s) {
+ String lines[] = s.split("\n");
+ Arrays.sort(lines);
+ List<String> linesL = Arrays.asList(lines);
+ StringBuilder buf = new StringBuilder();
+ for (String l : linesL) {
+ buf.append(l);
+ buf.append('\n');
+ }
+ return buf.toString();
+ }
+
+ public static <T extends GrammarAST> List<String> nodesToStrings(List<T> nodes) {
+ if ( nodes == null ) return null;
+ List<String> a = new ArrayList<String>();
+ for (T t : nodes) a.add(t.getText());
+ return a;
+ }
+
+// public static <T> List<T> list(T... values) {
+// List<T> x = new ArrayList<T>(values.length);
+// for (T v : values) {
+// if ( v!=null ) x.add(v);
+// }
+// return x;
+// }
+
+ public static String capitalize(String s) {
+ return Character.toUpperCase(s.charAt(0)) + s.substring(1);
+ }
+
+ public static String decapitalize(String s) {
+ return Character.toLowerCase(s.charAt(0)) + s.substring(1);
+ }
+
+ /** apply methodName to list and return list of results. method has
+ * no args. This pulls data out of a list essentially.
+ */
+ public static <From,To> List<To> select(List<From> list, Func1<From, To> selector) {
+ if ( list==null ) return null;
+ List<To> b = new ArrayList<To>();
+ for (From f : list) {
+ b.add(selector.exec(f));
+ }
+ return b;
+ }
+
+ /** Find exact object type or sublass of cl in list */
+ public static <T> T find(List<?> ops, Class<T> cl) {
+ for (Object o : ops) {
+ if ( cl.isInstance(o) ) return cl.cast(o);
+// if ( o.getClass() == cl ) return o;
+ }
+ return null;
+ }
+
+ public static <T> int indexOf(List<? extends T> elems, Filter<T> filter) {
+ for (int i=0; i<elems.size(); i++) {
+ if ( filter.select(elems.get(i)) ) return i;
+ }
+ return -1;
+ }
+
+ public static <T> int lastIndexOf(List<? extends T> elems, Filter<T> filter) {
+ for (int i=elems.size()-1; i>=0; i--) {
+ if ( filter.select(elems.get(i)) ) return i;
+ }
+ return -1;
+ }
+
+ public static void setSize(List<?> list, int size) {
+ if (size < list.size()) {
+ list.subList(size, list.size()).clear();
+ } else {
+ while (size > list.size()) {
+ list.add(null);
+ }
+ }
+ }
+
+}
diff --git a/tool/src/org/antlr/v4/parse/ANTLRLexer.g b/tool/src/org/antlr/v4/parse/ANTLRLexer.g
new file mode 100644
index 0000000..4768d2e
--- /dev/null
+++ b/tool/src/org/antlr/v4/parse/ANTLRLexer.g
@@ -0,0 +1,798 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// File : A3Lexer.g
+// Author : Jim Idle (jimi@temporal-wave.com)
+// Copyright : Free BSD - See @header clause below
+// Version : First implemented as part of ANTLR 3.2 this is the self
+// hosting ANTLR 3 Lexer.
+//
+// Description
+// -----------
+// This is the definitive lexer grammar for parsing ANTLR V3.x.x grammars. All other
+// gramnmars are derived from this grammar via source code control integration (perforce)
+// or by the gdiff tool.
+//
+// This grammar and its associated grmmmars A3Parser.g and A3Walker.g exhibit the following
+// traits, which are recommended for all production quality grammars:
+//
+// 1) They are separate grammars, not composite grammars;
+// 2) They implement all supporting methods in a superclass (at least this is recommended
+// for language targets that support inheritence;
+// 3) All errors are pushed as far down the parsing chain as possible, which means
+// that the lexer tries to defer error reporting to the parser, and the parser
+// tries to defer error reporting to a semantic phase consisting of a single
+// walk of the AST. The reason for this is that the error messages produced
+// from later phases of the parse will generally have better context and so
+// be more useful to the end user. Consider the message: "Syntax error at 'options'"
+// vs: "You cannot specify two options{} sections in a single grammar file".
+// 4) The lexer is 'programmed' to catch common mistakes such as unterminated literals
+// and report them specifically and not just issue confusing lexer mismatch errors.
+//
+
+/** Read in an ANTLR grammar and build an AST. Try not to do
+ * any actions, just build the tree.
+ *
+ * The phases are:
+ *
+ * A3Lexer.g (this file)
+ * A3Parser.g
+ * A3Verify.g (derived from A3Walker.g)
+ * assign.types.g
+ * define.g
+ * buildnfa.g
+ * antlr.print.g (optional)
+ * codegen.g
+ *
+ * Terence Parr
+ * University of San Francisco
+ * 2005
+ * Jim Idle (this v3 grammar)
+ * Temporal Wave LLC
+ * 2009
+ */
+lexer grammar ANTLRLexer;
+
+// ==============================================================================
+// Note that while this grammar does not care about order of constructs
+// that don't really matter, such as options before @header etc, it must first
+// be parsed by the original v2 parser, before it replaces it. That parser does
+// care about order of structures. Hence we are constrained by the v2 parser
+// for at least the first bootstrap release that causes this parser to replace
+// the v2 version.
+// ==============================================================================
+
+// -------
+// Options
+//
+// V3 option directives to tell the tool what we are asking of it for this
+// grammar.
+//
+options {
+
+ // Target language is Java, which is the default but being specific
+ // here as this grammar is also meant as a good example grammar for
+ // for users.
+ //
+ language = Java;
+
+ // The super class that this lexer should expect to inherit from, and
+ // which contains any and all support routines for the lexer. This is
+ // commented out in this baseline (definitive or normative grammar)
+ // - see the ANTLR tool implementation for hints on how to use the super
+ // class
+ //
+ //superclass = AbstractA3Lexer;
+}
+
+tokens { SEMPRED; TOKEN_REF; RULE_REF; LEXER_CHAR_SET; ARG_ACTION; }
+
+// Include the copyright in this source and also the generated source
+//
+@lexer::header {
+/*
+ [The "BSD licence"]
+ Copyright (c) 2005-2009 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+package org.antlr.v4.parse;
+import org.antlr.v4.tool.*;
+}
+
+
+@members {
+ public static final int COMMENTS_CHANNEL = 2;
+
+ public CommonTokenStream tokens; // track stream we push to; need for context info
+ public boolean isLexerRule = false;
+
+ public void grammarError(ErrorType etype, org.antlr.runtime.Token token, Object... args) { }
+
+ /** scan backwards from current point in this.tokens list
+ * looking for the start of the rule or subrule.
+ * Return token or null if for some reason we can't find the start.
+ */
+ public Token getRuleOrSubruleStartToken() {
+ if ( tokens==null ) return null;
+ int i = tokens.index();
+ int n = tokens.size();
+ if ( i>=n ) i = n-1; // seems index == n as we lex
+ while ( i>=0 && i<n) {
+ int ttype = tokens.get(i).getType();
+ if ( ttype == LPAREN || ttype == TOKEN_REF || ttype == RULE_REF ) {
+ return tokens.get(i);
+ }
+ i--;
+ }
+ return null;
+ }
+}
+
+// --------
+// Comments
+//
+// ANTLR comments can be multi or single line and we don't care
+// which particularly. However we also accept Javadoc style comments
+// of the form: /** ... */ and we do take care to distinguish those
+// from ordinary multi-line comments
+// Note how we guide the lexical PATH because we want to issue a decriptive
+// error message in case of a standalone '/' character, which makes no
+// sense in ANTLR source code. We alo trap unterminated multi-line comments
+//
+fragment DOC_COMMENT : ;
+COMMENT
+@init {
+
+ // Record the start line and offsets as if we need to report an
+ // unterminated comment, then we want to show the start of the comment
+ // we think is broken, not the end, where people will have to try and work
+ // it out themselves.
+ //
+ int startLine = $line;
+ int offset = getCharPositionInLine();
+}
+ : // Eat the first character only, then see if we have a comment
+ // or something silly.
+ //
+ '/' // Comment introducer
+
+ (
+ // Single line comment, possibly with embedded src/line directives
+ // in a similar style to the C pre-processor, allowing generated
+ // code to refer the programmer back to the original source code
+ // in case of error.
+ //
+ '/'
+ (
+ (' $ANTLR')=> ' $ANTLR' SRC
+ | ~(NLCHARS)*
+ )
+
+ | // Multi-line comment, which may be a documentation comment
+ // if it starts /** (note that we protect against accidentaly
+ // recognizing a comment /**/ as a documentation comment
+ //
+ '*' (
+ { input.LA(2) != '/'}?=> '*' { $type = DOC_COMMENT; }
+ | { true }?=> // Required to cover all alts with predicates
+ )
+
+ // Should we support embedded multiline comments here?
+ //
+ (
+ // Pick out end of multiline comment and exit the loop
+ // if we find it.
+ //
+ { !(input.LA(1) == '*' && input.LA(2) == '/') }?
+
+ // Anything else other than the non-greedy match of
+ // the comment close sequence
+ //
+ .
+ )*
+ (
+ // Look for the comment terminator, but if it is accidentally
+ // unterminated, then we will hit EOF, which will trigger the
+ // epsilon alt and hence we can issue an error message relative
+ // to the start of the unterminated multi-line comment
+ //
+ '*/'
+
+ | // Unterminated comment!
+ //
+ {
+ // ErrorManager.msg(Msg.UNTERMINATED_DOC_COMMENT, startLine, offset, $pos, startLine, offset, $pos, (Object)null);
+ }
+ )
+
+ | // There was nothing that made sense following the opening '/' and so
+ // we issue an error regarding the malformed comment
+ //
+ {
+ // TODO: Insert error message relative to comment start
+ //
+ }
+ )
+ {
+ // We do not wish to pass the comments in to the parser. If you are
+ // writing a formatter then you will want to preserve the comments off
+ // channel, but could just skip and save token space if not.
+ //
+ $channel=COMMENTS_CHANNEL;
+ }
+ ;
+
+ARG_OR_CHARSET
+options {k=1;}
+ : {isLexerRule}?=> LEXER_CHAR_SET {$type=LEXER_CHAR_SET;}
+ | {!isLexerRule}?=> ARG_ACTION
+ {
+ $type=ARG_ACTION;
+ // Set the token text to our gathered string minus outer [ ]
+ String t = $text;
+ t = t.substring(1,t.length()-1);
+ setText(t);
+ }
+ ;
+
+fragment
+LEXER_CHAR_SET
+ : '['
+ ( '\\' ~('\r'|'\n')
+ | ~('\r'|'\n'|'\\'|']')
+ )*
+ ']'
+ ;
+
+// --------------
+// Argument specs
+//
+// Certain argument lists, such as those specifying call parameters
+// to a rule invocation, or input parameters to a rule specification
+// are contained within square brackets. In the lexer we consume them
+// all at once and sort them out later in the grammar analysis.
+//
+fragment
+ARG_ACTION
+ : '['
+ (
+ ARG_ACTION
+
+ | ('"')=>ACTION_STRING_LITERAL
+
+ | ('\'')=>ACTION_CHAR_LITERAL
+
+ | ~('['|']')
+ )*
+
+ ']'
+ ;
+
+// -------
+// Actions
+//
+// Other than making sure to distinguish between { and } embedded
+// within what we have assumed to be literals in the action code, the
+// job of the lexer is merely to gather the code within the action
+// (delimited by {}) and pass it to the parser as a single token.
+// We know that this token will be asked for its text somewhere
+// in the upcoming parse, so setting the text here to exclude
+// the delimiting {} is no additional overhead.
+//
+ACTION
+ : NESTED_ACTION
+ ( '?' {$type = SEMPRED;}
+ ( (WSNLCHARS* '=>') => WSNLCHARS* '=>' // v3 gated sempred
+ {
+ Token t = new CommonToken(input, state.type, state.channel, state.tokenStartCharIndex, getCharIndex()-1);
+ t.setLine(state.tokenStartLine);
+ t.setText(state.text);
+ t.setCharPositionInLine(state.tokenStartCharPositionInLine);
+ grammarError(ErrorType.V3_GATED_SEMPRED, t);
+ }
+ )?
+ )?
+ ;
+
+// ----------------
+// Action structure
+//
+// Many language targets use {} as block delimiters and so we
+// must recursively match {} delimited blocks to balance the
+// braces. Additionally, we must make some assumptions about
+// literal string representation in the target language. We assume
+// that they are delimited by ' or " and so consume these
+// in their own alts so as not to inadvertantly match {}.
+// This rule calls itself on matching a {
+//
+fragment
+NESTED_ACTION
+@init {
+
+ // Record the start line and offsets as if we need to report an
+ // unterminated block, then we want to show the start of the comment
+ // we think is broken, not the end, where people will have to try and work
+ // it out themselves.
+ //
+ int startLine = getLine();
+ int offset = getCharPositionInLine();
+}
+
+ : // Action and other blocks start with opening {
+ //
+ '{'
+ (
+ // And now we can match one of a number of embedded
+ // elements within the action until we find a
+ // } that balances the opening {. If we do not find
+ // the balanced } then we will hit EOF and can issue
+ // an error message about the brace that we belive to
+ // be mismatched. This won't be foolproof but we will
+ // be able to at least report an error against the
+ // opening brace that we feel is in error and this will
+ // guide the user to the correction as best we can.
+ //
+
+
+ // An embedded {} block
+ //
+ NESTED_ACTION
+
+ | // What appears to be a literal
+ //
+ ACTION_CHAR_LITERAL
+
+ | // We have assumed that the target language has C/Java
+ // type comments.
+ //
+ COMMENT
+
+ | // What appears to be a literal
+ //
+ ACTION_STRING_LITERAL
+
+ | // What appears to be an escape sequence
+ //
+ ACTION_ESC
+
+ | // Some other single character that is not
+ // handled above
+ //
+ ~('\\'|'"'|'\''|'/'|'{'|'}')
+
+ )*
+
+ (
+ // Correctly balanced closing brace
+ //
+ '}'
+
+ | // Looks like have an imblanced {} block, report
+ // with respect to the opening brace.
+ //
+ {
+ // TODO: Report imbalanced {}
+ System.out.println("Block starting at line " + startLine + " offset " + (offset+1) + " contains imbalanced {} or is missing a }");
+ }
+ )
+ ;
+
+
+// Keywords
+// --------
+// keywords used to specify ANTLR v3 grammars. Keywords may not be used as
+// labels for rules or in any other context where they would be ambiguous
+// with the keyword vs some other identifier
+// OPTIONS, TOKENS, and CHANNELS must also consume the opening brace that captures
+// their option block, as this is the easiest way to parse it separate
+// to an ACTION block, despite it using the same {} delimiters.
+//
+OPTIONS : 'options' WSNLCHARS* '{' ;
+TOKENS_SPEC : 'tokens' WSNLCHARS* '{' ;
+CHANNELS : 'channels' WSNLCHARS* '{' ;
+
+IMPORT : 'import' ;
+FRAGMENT : 'fragment' ;
+LEXER : 'lexer' ;
+PARSER : 'parser' ;
+GRAMMAR : 'grammar' ;
+TREE_GRAMMAR : 'tree' WSNLCHARS* 'grammar' ;
+PROTECTED : 'protected' ;
+PUBLIC : 'public' ;
+PRIVATE : 'private' ;
+RETURNS : 'returns' ;
+LOCALS : 'locals' ;
+THROWS : 'throws' ;
+CATCH : 'catch' ;
+FINALLY : 'finally' ;
+MODE : 'mode' ;
+
+// -----------
+// Punctuation
+//
+// Character sequences used as separators, delimters, operators, etc
+//
+COLON : ':'
+ {
+ // scan backwards, looking for a RULE_REF or TOKEN_REF.
+ // which would indicate the start of a rule definition.
+ // If we see a LPAREN, then it's the start of the subrule.
+ // this.tokens is the token string we are pushing into, so
+ // just loop backwards looking for a rule definition. Then
+ // we set isLexerRule.
+ Token t = getRuleOrSubruleStartToken();
+ if ( t!=null ) {
+ if ( t.getType()==RULE_REF ) isLexerRule = false;
+ else if ( t.getType()==TOKEN_REF ) isLexerRule = true;
+ // else must be subrule; don't alter context
+ }
+ }
+ ;
+COLONCOLON : '::' ;
+COMMA : ',' ;
+SEMI : ';' ;
+LPAREN : '(' ;
+RPAREN : ')' ;
+RARROW : '->' ;
+LT : '<' ;
+GT : '>' ;
+ASSIGN : '=' ;
+QUESTION : '?' ;
+SYNPRED : '=>'
+ {
+ Token t = new CommonToken(input, state.type, state.channel,
+ state.tokenStartCharIndex, getCharIndex()-1);
+ t.setLine(state.tokenStartLine);
+ t.setText(state.text);
+ t.setCharPositionInLine(state.tokenStartCharPositionInLine);
+ grammarError(ErrorType.V3_SYNPRED, t);
+ $channel=HIDDEN;
+ }
+ ;
+STAR : '*' ;
+PLUS : '+' ;
+PLUS_ASSIGN : '+=' ;
+OR : '|' ;
+DOLLAR : '$' ;
+DOT : '.' ; // can be WILDCARD or DOT in qid or imported rule ref
+RANGE : '..' ;
+AT : '@' ;
+POUND : '#' ;
+NOT : '~' ;
+RBRACE : '}' ;
+
+/** Allow unicode rule/token names */
+ID : a=NameStartChar NameChar*
+ {
+ if ( Grammar.isTokenName($a.text) ) $type = TOKEN_REF;
+ else $type = RULE_REF;
+ }
+ ;
+
+fragment
+NameChar : NameStartChar
+ | '0'..'9'
+ | '_'
+ | '\u00B7'
+ | '\u0300'..'\u036F'
+ | '\u203F'..'\u2040'
+ ;
+
+fragment
+NameStartChar
+ : 'A'..'Z' | 'a'..'z'
+ | '\u00C0'..'\u00D6'
+ | '\u00D8'..'\u00F6'
+ | '\u00F8'..'\u02FF'
+ | '\u0370'..'\u037D'
+ | '\u037F'..'\u1FFF'
+ | '\u200C'..'\u200D'
+ | '\u2070'..'\u218F'
+ | '\u2C00'..'\u2FEF'
+ | '\u3001'..'\uD7FF'
+ | '\uF900'..'\uFDCF'
+ | '\uFDF0'..'\uFEFE'
+ | '\uFF00'..'\uFFFD'
+ ; // ignores | ['\u10000-'\uEFFFF] ;
+
+// ----------------------------
+// Literals embedded in actions
+//
+// Note that we have made the assumption that the language used within
+// actions uses the fairly standard " and ' delimiters for literals and
+// that within these literals, characters are escaped using the \ character.
+// There are some languages which do not conform to this in all cases, such
+// as by using /string/ and so on. We will have to deal with such cases if
+// if they come up in targets.
+//
+
+// Within actions, or other structures that are not part of the ANTLR
+// syntax, we may encounter literal characters. Within these, we do
+// not want to inadvertantly match things like '}' and so we eat them
+// specifically. While this rule is called CHAR it allows for the fact that
+// some languages may use/allow ' as the string delimiter.
+//
+fragment
+ACTION_CHAR_LITERAL
+ : '\'' (('\\')=>ACTION_ESC | ~'\'' )* '\''
+ ;
+
+// Within actions, or other structures that are not part of the ANTLR
+// syntax, we may encounter literal strings. Within these, we do
+// not want to inadvertantly match things like '}' and so we eat them
+// specifically.
+//
+fragment
+ACTION_STRING_LITERAL
+ : '"' (('\\')=>ACTION_ESC | ~'"')* '"'
+ ;
+
+// Within literal strings and characters that are not part of the ANTLR
+// syntax, we must allow for escaped character sequences so that we do not
+// inadvertantly recognize the end of a string or character when the terminating
+// delimiter has been esacped.
+//
+fragment
+ACTION_ESC
+ : '\\' .
+ ;
+
+// -------
+// Integer
+//
+// Obviously (I hope) match an aribtrary long sequence of digits.
+//
+INT : ('0'..'9')+
+ ;
+
+// -----------
+// Source spec
+//
+// A fragment rule for picking up information about an origrinating
+// file from which the grammar we are parsing has been generated. This allows
+// ANTLR to report errors against the originating file and not the generated
+// file.
+//
+fragment
+SRC : 'src' WSCHARS+ file=ACTION_STRING_LITERAL WSCHARS+ line=INT
+ {
+ // TODO: Add target specific code to change the source file name and current line number
+ //
+ }
+ ;
+
+// --------------
+// Literal string
+//
+// ANTLR makes no disticintion between a single character literal and a
+// multi-character string. All literals are single quote delimited and
+// may contain unicode escape sequences of the form \uxxxx, where x
+// is a valid hexadecimal number (as per Java basically).
+STRING_LITERAL
+ : '\'' ( ( ESC_SEQ | ~('\\'|'\''|'\r'|'\n') ) )*
+ ( '\''
+ | // Unterminated string literal
+ {
+ Token t = new CommonToken(input, state.type, state.channel, state.tokenStartCharIndex, getCharIndex()-1);
+ t.setLine(state.tokenStartLine);
+ t.setText(state.text);
+ t.setCharPositionInLine(state.tokenStartCharPositionInLine);
+ grammarError(ErrorType.UNTERMINATED_STRING_LITERAL, t);
+ }
+ )
+ ;
+
+// A valid hex digit specification
+//
+fragment
+HEX_DIGIT : ('0'..'9'|'a'..'f'|'A'..'F') ;
+
+// Any kind of escaped character that we can embed within ANTLR
+// literal strings.
+//
+fragment
+ESC_SEQ
+ : '\\'
+ (
+ // The standard escaped character set such as tab, newline,
+ // etc.
+ //
+ 'b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\'
+
+ | // A Java style Unicode escape sequence
+ //
+ UNICODE_ESC
+
+ | // An illegal escape seqeunce
+ //
+ {
+ Token t = new CommonToken(input, state.type, state.channel, getCharIndex()-1, getCharIndex());
+ t.setText(t.getText());
+ t.setLine(input.getLine());
+ t.setCharPositionInLine(input.getCharPositionInLine()-1);
+ grammarError(ErrorType.INVALID_ESCAPE_SEQUENCE, t);
+ }
+ )
+ ;
+
+fragment
+UNICODE_ESC
+
+@init {
+
+ // Flag to tell us whether we have a valid number of
+ // hex digits in the escape sequence
+ //
+ int hCount = 0;
+}
+ : 'u' // Leadin for unicode escape sequence
+
+ // We now require 4 hex digits. Note though
+ // that we accept any number of characters
+ // and issue an error if we do not get 4. We cannot
+ // use an inifinite count such as + because this
+ // might consume too many, so we lay out the lexical
+ // options and issue an error at the invalid paths.
+ //
+ (
+ (
+ HEX_DIGIT { hCount++; }
+ (
+ HEX_DIGIT { hCount++; }
+ (
+ HEX_DIGIT { hCount++; }
+ (
+ // Four valid hex digits, we are good
+ //
+ HEX_DIGIT { hCount++; }
+
+ | // Three valid digits
+ )
+
+ | // Two valid digits
+ )
+
+ | // One valid digit
+ )
+ )
+ | // No valid hex digits at all
+ )
+
+ // Now check the digit count and issue an error if we need to
+ //
+ {
+ if (hCount != 4) {
+ Token t = new CommonToken(input, state.type, state.channel, getCharIndex()-3-hCount, getCharIndex()-1);
+ t.setText(t.getText());
+ t.setLine(input.getLine());
+ t.setCharPositionInLine(input.getCharPositionInLine()-hCount-2);
+ grammarError(ErrorType.INVALID_ESCAPE_SEQUENCE, t);
+ }
+ }
+ ;
+
+// ----------
+// Whitespace
+//
+// Characters and character constructs that are of no import
+// to the parser and are used to make the grammar easier to read
+// for humans.
+//
+WS
+ : (
+ ' '
+ | '\t'
+ | '\r'
+ | '\n'
+ | '\f'
+ )+
+ {$channel=HIDDEN;}
+ ;
+
+// A fragment rule for use in recognizing end of line in
+// rules like COMMENT.
+//
+fragment
+NLCHARS
+ : '\n' | '\r'
+ ;
+
+// A fragment rule for recognizing traditional whitespace
+// characters within lexer rules.
+//
+fragment
+WSCHARS
+ : ' ' | '\t' | '\f'
+ ;
+
+// A fragment rule for recognizing both traditional whitespace and
+// end of line markers, when we don't care to distinguish but don't
+// want any action code going on.
+//
+fragment
+WSNLCHARS
+ : ' ' | '\t' | '\f' | '\n' | '\r'
+ ;
+
+// This rule allows ANTLR 4 to parse grammars using the UTF-8 encoding with a
+// byte order mark. Since this Unicode character doesn't appear as a token
+// anywhere else in the grammar, we can simply skip all instances of it without
+// problem. This rule will not break usage of \uFEFF inside a LEXER_CHAR_SET or
+// STRING_LITERAL.
+UnicodeBOM
+ : '\uFEFF' {skip();}
+ ;
+
+// -----------------
+// Illegal Character
+//
+// This is an illegal character trap which is always the last rule in the
+// lexer specification. It matches a single character of any value and being
+// the last rule in the file will match when no other rule knows what to do
+// about the character. It is reported as an error but is not passed on to the
+// parser. This means that the parser to deal with the gramamr file anyway
+// but we will not try to analyse or code generate from a file with lexical
+// errors.
+//
+ERRCHAR
+ : .
+ {
+ Token t = new CommonToken(input, state.type, state.channel, state.tokenStartCharIndex, getCharIndex()-1);
+ t.setLine(state.tokenStartLine);
+ t.setText(state.text);
+ t.setCharPositionInLine(state.tokenStartCharPositionInLine);
+ String msg = getTokenErrorDisplay(t) + " came as a complete surprise to me";
+ grammarError(ErrorType.SYNTAX_ERROR, t, msg);
+ state.syntaxErrors++;
+ skip();
+ }
+ ;
diff --git a/tool/src/org/antlr/v4/parse/ANTLRParser.g b/tool/src/org/antlr/v4/parse/ANTLRParser.g
new file mode 100644
index 0000000..42946fa
--- /dev/null
+++ b/tool/src/org/antlr/v4/parse/ANTLRParser.g
@@ -0,0 +1,922 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** The definitive ANTLR v3 grammar to parse ANTLR v4 grammars.
+ * The grammar builds ASTs that are sniffed by subsequent stages.
+ */
+parser grammar ANTLRParser;
+
+options {
+ // Target language is Java, which is the default but being specific
+ // here as this grammar is also meant as a good example grammar for
+ // for users.
+ language = Java;
+
+ // The output of this grammar is going to be an AST upon which
+ // we run a semantic checking phase, then the rest of the analysis
+ // including final code generation.
+ output = AST;
+
+ // The vocabulary (tokens and their int token types) we are using
+ // for the parser. This is generated by the lexer. The vocab will be extended
+ // to include the imaginary tokens below.
+ tokenVocab = ANTLRLexer;
+
+ ASTLabelType = GrammarAST;
+}
+
+// Imaginary Tokens
+//
+// Imaginary tokens do not exist as far as the lexer is concerned, and it cannot
+// generate them. However we sometimes need additional 'tokens' to use as root
+// nodes for the AST we are generating. The tokens section is where we
+// specify any such tokens
+tokens {
+ RULE;
+ PREC_RULE; // flip to this if we find that it's left-recursive
+ RULES;
+ RULEMODIFIERS;
+ RULEACTIONS;
+ BLOCK;
+ OPTIONAL;
+ CLOSURE;
+ POSITIVE_CLOSURE;
+ RANGE;
+ SET;
+ CHAR_RANGE;
+ EPSILON;
+ ALT;
+ ALTLIST;
+ ID;
+ ARG;
+ ARGLIST;
+ RET;
+ COMBINED;
+ INITACTION;
+ LABEL; // $x used in rewrite rules
+ TEMPLATE;
+ WILDCARD;
+ // A generic node indicating a list of something when we don't
+ // really need to distinguish what we have a list of as the AST
+ // will 'kinow' by context.
+ //
+ LIST;
+ ELEMENT_OPTIONS; // TOKEN<options>
+ RESULT;
+
+ // lexer action stuff
+ LEXER_ALT_ACTION;
+ LEXER_ACTION_CALL; // ID(foo)
+}
+
+// Include the copyright in this source and also the generated source
+//
+@header {
+/*
+ [The "BSD licence"]
+ Copyright (c) 2005-20012 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+package org.antlr.v4.parse;
+
+import org.antlr.v4.tool.*;
+import org.antlr.v4.tool.ast.*;
+
+import java.util.ArrayDeque;
+import java.util.Deque;
+}
+
+@members {
+Deque<String> paraphrases = new ArrayDeque<String>();
+public void grammarError(ErrorType etype, org.antlr.runtime.Token token, Object... args) { }
+}
+
+// The main entry point for parsing a V3 grammar from top to toe. This is
+// the method call from whence to obtain the AST for the parse.
+//
+grammarSpec
+@after {
+GrammarAST options = (GrammarAST)$tree.getFirstChildWithType(ANTLRParser.OPTIONS);
+if ( options!=null ) {
+ Grammar.setNodeOptions($tree, options);
+}
+}
+ : // First we should see the type and name of the grammar file that
+ // we are about to parse.
+ //
+ grammarType id SEMI
+
+ // There now follows zero or more declaration sections that should
+ // be given to us before the rules are declared
+ //
+// A number of things can be declared/stated before the grammar rules
+// 'proper' are parsed. These include grammar imports (delegate), grammar
+// options, imaginary token declarations, global scope declarations,
+// and actions such as @header. In this rule we allow any number of
+// these constructs in any order so that the grammar author is not
+// constrained by some arbitrary order of declarations that nobody
+// can remember. In the next phase of the parse, we verify that these
+// constructs are valid, not repeated and so on.
+ sync ( prequelConstruct sync )*
+
+ // We should now see at least one ANTLR EBNF style rule
+ // declaration. If the rules are missing we will let the
+ // semantic verification phase tell the user about it.
+ //
+ rules
+
+ modeSpec*
+
+ // And we force ANTLR to process everything it finds in the input
+ // stream by specifying hte need to match End Of File before the
+ // parse is complete.
+ //
+ EOF
+
+ // Having parsed everything in the file and accumulated the relevant
+ // subtrees, we can now rewrite everything into the main AST form
+ // that our tree walkers are expecting.
+ //
+
+ -> ^(grammarType // The grammar type is our root AST node
+ id // We need to identify the grammar of course
+ prequelConstruct* // The set of declarations we accumulated
+ rules // And of course, we need the set of rules we discovered
+ modeSpec*
+ )
+ ;
+
+grammarType
+@after {
+ if ( $tg!=null ) throw new v3TreeGrammarException(tg);
+ if ( $t!=null ) ((GrammarRootAST)$tree).grammarType = $t.type;
+ else ((GrammarRootAST)$tree).grammarType=COMBINED;
+}
+ : ( t=LEXER g=GRAMMAR -> GRAMMAR<GrammarRootAST>[$g, "LEXER_GRAMMAR", getTokenStream()]
+ | // A standalone parser specification
+ t=PARSER g=GRAMMAR -> GRAMMAR<GrammarRootAST>[$g, "PARSER_GRAMMAR", getTokenStream()]
+
+ // A combined lexer and parser specification
+ | g=GRAMMAR -> GRAMMAR<GrammarRootAST>[$g, "COMBINED_GRAMMAR", getTokenStream()]
+ | tg=TREE_GRAMMAR
+
+ )
+ ;
+
+// This is the list of all constructs that can be declared before
+// the set of rules that compose the grammar, and is invoked 0..n
+// times by the grammarPrequel rule.
+prequelConstruct
+ : // A list of options that affect analysis and/or code generation
+ optionsSpec
+
+ | // A list of grammars to which this grammar will delegate certain
+ // parts of the parsing sequence - a set of imported grammars
+ delegateGrammars
+
+ | // The declaration of any token types we need that are not already
+ // specified by a preceeding grammar, such as when a parser declares
+ // imaginary tokens with which to construct the AST, or a rewriting
+ // tree parser adds further imaginary tokens to ones defined in a prior
+ // {tree} parser.
+ tokensSpec
+
+ | // A list of custom channels used by the grammar
+ channelsSpec
+
+ | // A declaration of language target implemented constructs. All such
+ // action sections start with '@' and are given to the language target's
+ // StringTemplate group. For instance @parser::header and @lexer::header
+ // are gathered here.
+ action
+ ;
+
+// A list of options that affect analysis and/or code generation
+optionsSpec
+ : OPTIONS (option SEMI)* RBRACE -> ^(OPTIONS[$OPTIONS, "OPTIONS"] option*)
+ ;
+
+option
+ : id ASSIGN^ optionValue
+ ;
+
+// ------------
+// Option Value
+//
+// The actual value of an option - Doh!
+//
+optionValue
+ : // If the option value is a single word that conforms to the
+ // lexical rules of token or rule names, then the user may skip quotes
+ // and so on. Many option values meet this description
+ qid
+ | STRING_LITERAL
+ | ACTION<ActionAST>
+ | INT
+ ;
+
+// A list of grammars to which this grammar will delegate certain
+// parts of the parsing sequence - a set of imported grammars
+delegateGrammars
+ : IMPORT delegateGrammar (COMMA delegateGrammar)* SEMI -> ^(IMPORT delegateGrammar+)
+ ;
+
+// A possibly named grammar file that should be imported to this gramamr
+// and delgated to for the rules it specifies
+delegateGrammar
+ : id ASSIGN^ id
+ | id
+ ;
+
+tokensSpec
+ : TOKENS_SPEC id (COMMA id)* RBRACE -> ^(TOKENS_SPEC id+)
+ | TOKENS_SPEC RBRACE ->
+ | TOKENS_SPEC^ v3tokenSpec+ RBRACE!
+ {grammarError(ErrorType.V3_TOKENS_SYNTAX, $TOKENS_SPEC);}
+ ;
+
+v3tokenSpec
+ : id
+ ( ASSIGN lit=STRING_LITERAL
+ {
+ grammarError(ErrorType.V3_ASSIGN_IN_TOKENS, $id.start,
+ $id.text, $lit.getText());
+ }
+ -> id // ignore assignment
+ | -> id
+ )
+ SEMI
+ ;
+
+channelsSpec
+ : CHANNELS^ id (COMMA! id)* RBRACE!
+ ;
+
+// A declaration of a language target specifc section,
+// such as @header, @includes and so on. We do not verify these
+// sections, they are just passed on to the language target.
+/** Match stuff like @parser::members {int i;} */
+action
+ : AT (actionScopeName COLONCOLON)? id ACTION -> ^(AT actionScopeName? id ACTION<ActionAST>)
+ ;
+
+/** Sometimes the scope names will collide with keywords; allow them as
+ * ids for action scopes.
+ */
+actionScopeName
+ : id
+ | LEXER -> ID[$LEXER]
+ | PARSER -> ID[$PARSER]
+ ;
+
+modeSpec
+ : MODE id SEMI sync (lexerRule sync)* -> ^(MODE id lexerRule*)
+ ;
+
+rules
+ : sync (rule sync)*
+ // Rewrite with an enclosing node as this is good for counting
+ // the number of rules and an easy marker for the walker to detect
+ // that there are no rules.
+ ->^(RULES rule*)
+ ;
+
+sync
+@init {
+ BitSet followSet = computeErrorRecoverySet();
+ if ( input.LA(1)!=Token.EOF && !followSet.member(input.LA(1)) ) {
+ reportError(new NoViableAltException("",0,0,input));
+ beginResync();
+ consumeUntil(input, followSet);
+ endResync();
+ }
+} :
+ ;
+
+rule: parserRule
+ | lexerRule
+ ;
+
+// The specification of an EBNF rule in ANTLR style, with all the
+// rule level parameters, declarations, actions, rewrite specs and so
+// on.
+//
+// Note that here we allow any number of rule declaration sections (such
+// as scope, returns, etc) in any order and we let the upcoming semantic
+// verification of the AST determine if things are repeated or if a
+// particular functional element is not valid in the context of the
+// grammar type, such as using returns in lexer rules and so on.
+parserRule
+@init { paraphrases.push("matching a rule"); }
+@after {
+ paraphrases.pop();
+ GrammarAST options = (GrammarAST)$tree.getFirstChildWithType(ANTLRParser.OPTIONS);
+ if ( options!=null ) {
+ Grammar.setNodeOptions($tree, options);
+ }
+}
+ : // Start with the rule name. Here we do not distinguish between
+ // parser or lexer rules, the semantic verification phase will
+ // reject any rules that make no sense, such as lexer rules in
+ // a pure parser or tree parser.
+ RULE_REF
+
+ // Immediately following the rulename, there may be a specification
+ // of input parameters for the rule. We do not do anything with the
+ // parameters here except gather them for future phases such as
+ // semantic verifcation, type assignment etc. We require that
+ // the input parameters are the next syntactically significant element
+ // following the rule id.
+ ARG_ACTION?
+
+ ruleReturns?
+
+ throwsSpec?
+
+ localsSpec?
+
+ // Now, before the rule specification itself, which is introduced
+ // with a COLON, we may have zero or more configuration sections.
+ // As usual we just accept anything that is syntactically valid for
+ // one form of the rule or another and let the semantic verification
+ // phase throw out anything that is invalid.
+// At the rule level, a programmer may specify a number of sections, such
+// as scope declarations, rule return elements, @ sections (which may be
+// language target specific) and so on. We allow any number of these in any
+// order here and as usual rely onthe semantic verification phase to reject
+// anything invalid using its addinotal context information. Here we are
+// context free and just accept anything that is a syntactically correct
+// construct.
+//
+ rulePrequels
+
+ COLON
+
+ // The rule is, at the top level, just a list of alts, with
+ // finer grained structure defined within the alts.
+ ruleBlock
+
+ SEMI
+
+ exceptionGroup
+
+ -> ^( RULE<RuleAST> RULE_REF ARG_ACTION<ActionAST>?
+ ruleReturns? throwsSpec? localsSpec? rulePrequels? ruleBlock exceptionGroup*
+ )
+ ;
+
+// Many language targets support exceptions and the rule will
+// generally be able to throw the language target equivalent
+// of a recognition exception. The grammar programmar can
+// specify a list of exceptions to catch or a generic catch all
+// and the target language code generation template is
+// responsible for generating code that makes sense.
+exceptionGroup
+ : exceptionHandler* finallyClause?
+ ;
+
+// Specifies a handler for a particular type of exception
+// thrown by a rule
+exceptionHandler
+ : CATCH ARG_ACTION ACTION -> ^(CATCH ARG_ACTION<ActionAST> ACTION<ActionAST>)
+ ;
+
+finallyClause
+ : FINALLY ACTION -> ^(FINALLY ACTION<ActionAST>)
+ ;
+
+rulePrequels
+@init { paraphrases.push("matching rule preamble"); }
+@after { paraphrases.pop(); }
+ : sync (rulePrequel sync)* -> rulePrequel*
+ ;
+
+// An individual rule level configuration as referenced by the ruleActions
+// rule above.
+//
+rulePrequel
+ : optionsSpec
+ | ruleAction
+ ;
+
+// A rule can return elements that it constructs as it executes.
+// The return values are specified in a 'returns' prequel element,
+// which contains COMMA separated declarations, where the declaration
+// is target language specific. Here we see the returns declaration
+// as a single lexical action element, to be processed later.
+//
+ruleReturns
+ : RETURNS^ ARG_ACTION<ActionAST>
+ ;
+
+// --------------
+// Exception spec
+//
+// Some target languages, such as Java and C# support exceptions
+// and they are specified as a prequel element for each rule that
+// wishes to throw its own exception type. Note that the name of the
+// exception is just a single word, so the header section of the grammar
+// must specify the correct import statements (or language equivalent).
+// Target languages that do not support exceptions just safely ignore
+// them.
+//
+throwsSpec
+ : THROWS qid (COMMA qid)* -> ^(THROWS qid+)
+ ;
+
+// locals [Cat x, float g]
+localsSpec : LOCALS^ ARG_ACTION<ActionAST> ;
+
+// @ Sections are generally target language specific things
+// such as local variable declarations, code to run before the
+// rule starts and so on. Fir instance most targets support the
+// @init {} section where declarations and code can be placed
+// to run before the rule is entered. The C target also has
+// an @declarations {} section, where local variables are declared
+// in order that the generated code is C89 copmliant.
+//
+/** Match stuff like @init {int i;} */
+ruleAction
+ : AT id ACTION -> ^(AT id ACTION<ActionAST>)
+ ;
+
+// A set of alts, rewritten as a BLOCK for generic processing
+// in tree walkers. Used by the rule 'rule' so that the list of
+// alts for a rule appears as a BLOCK containing the alts and
+// can be processed by the generic BLOCK rule. Note that we
+// use a separate rule so that the BLOCK node has start and stop
+// boundaries set correctly by rule post processing of rewrites.
+ruleBlock
+@init {Token colon = input.LT(-1);}
+ : ruleAltList -> ^(BLOCK<BlockAST>[colon,"BLOCK"] ruleAltList)
+ ;
+ catch [ResyncToEndOfRuleBlock e] {
+ // just resyncing; ignore error
+ retval.tree = (GrammarAST)adaptor.errorNode(input, retval.start, input.LT(-1), null);
+ }
+
+ruleAltList
+ : labeledAlt (OR labeledAlt)* -> labeledAlt+
+ ;
+
+labeledAlt
+ : alternative
+ ( POUND! id! {((AltAST)$alternative.tree).altLabel=$id.tree;}
+ )?
+ ;
+
+lexerRule
+@init { paraphrases.push("matching a lexer rule"); }
+@after {
+ paraphrases.pop();
+}
+ : FRAGMENT?
+ TOKEN_REF COLON lexerRuleBlock SEMI
+ -> ^( RULE<RuleAST> TOKEN_REF
+ ^(RULEMODIFIERS FRAGMENT)? lexerRuleBlock
+ )
+ ;
+
+lexerRuleBlock
+@init {Token colon = input.LT(-1);}
+ : lexerAltList -> ^(BLOCK<BlockAST>[colon,"BLOCK"] lexerAltList)
+ ;
+ catch [ResyncToEndOfRuleBlock e] {
+ // just resyncing; ignore error
+ retval.tree = (GrammarAST)adaptor.errorNode(input, retval.start, input.LT(-1), null);
+ }
+
+lexerAltList
+ : lexerAlt (OR lexerAlt)* -> lexerAlt+
+ ;
+
+lexerAlt
+ : lexerElements
+ ( lexerCommands -> ^(LEXER_ALT_ACTION<AltAST> lexerElements lexerCommands)
+ | -> lexerElements
+ )
+ ;
+
+lexerElements
+ : lexerElement+ -> ^(ALT<AltAST> lexerElement+)
+ | -> ^(ALT<AltAST> EPSILON) // empty alt
+ ;
+
+lexerElement
+@init {
+ paraphrases.push("looking for lexer rule element");
+ int m = input.mark();
+}
+@after { paraphrases.pop(); }
+ : labeledLexerElement
+ ( ebnfSuffix -> ^( ebnfSuffix ^(BLOCK<BlockAST>[$labeledLexerElement.start,"BLOCK"] ^(ALT<AltAST> labeledLexerElement) ) )
+ | -> labeledLexerElement
+ )
+ | lexerAtom
+ ( ebnfSuffix -> ^( ebnfSuffix ^(BLOCK<BlockAST>[$lexerAtom.start,"BLOCK"] ^(ALT<AltAST> lexerAtom) ) )
+ | -> lexerAtom
+ )
+ | lexerBlock
+ ( ebnfSuffix -> ^(ebnfSuffix lexerBlock)
+ | -> lexerBlock
+ )
+ | actionElement // actions only allowed at end of outer alt actually,
+ // but preds can be anywhere
+ ;
+ catch [RecognitionException re] {
+ retval.tree = (GrammarAST)adaptor.errorNode(input, retval.start, input.LT(-1), re);
+ int ttype = input.get(input.range()).getType(); // seems to be next token
+ // look for anything that really belongs at the start of the rule minus the initial ID
+ if ( ttype==COLON || ttype==RETURNS || ttype==CATCH || ttype==FINALLY || ttype==AT || ttype==EOF ) {
+ RecognitionException missingSemi =
+ new v4ParserException("unterminated rule (missing ';') detected at '"+
+ input.LT(1).getText()+" "+input.LT(2).getText()+"'", input);
+ reportError(missingSemi);
+ if ( ttype==EOF ) {
+ input.seek(input.index()+1);
+ }
+ else if ( ttype==CATCH || ttype==FINALLY ) {
+ input.seek(input.range()); // ignore what's before rule trailer stuff
+ }
+ else if ( ttype==RETURNS || ttype==AT ) { // scan back looking for ID of rule header
+ int p = input.index();
+ Token t = input.get(p);
+ while ( t.getType()!=RULE_REF && t.getType()!=TOKEN_REF ) {
+ p--;
+ t = input.get(p);
+ }
+ input.seek(p);
+ }
+ throw new ResyncToEndOfRuleBlock(); // make sure it goes back to rule block level to recover
+ }
+ reportError(re);
+ recover(input,re);
+ }
+
+labeledLexerElement
+ : id (ass=ASSIGN|ass=PLUS_ASSIGN)
+ ( lexerAtom -> ^($ass id lexerAtom)
+ | lexerBlock -> ^($ass id lexerBlock)
+ )
+ ;
+
+
+lexerBlock
+@after {
+GrammarAST options = (GrammarAST)$tree.getFirstChildWithType(ANTLRParser.OPTIONS);
+if ( options!=null ) {
+ Grammar.setNodeOptions($tree, options);
+}
+}
+ : LPAREN
+ ( optionsSpec COLON )?
+ lexerAltList
+ RPAREN
+ -> ^(BLOCK<BlockAST>[$LPAREN,"BLOCK"] optionsSpec? lexerAltList )
+ ;
+
+// channel=HIDDEN, skip, more, mode(INSIDE), push(INSIDE), pop
+lexerCommands
+ : RARROW lexerCommand (COMMA lexerCommand)* -> lexerCommand+
+ ;
+
+lexerCommand
+ : lexerCommandName LPAREN lexerCommandExpr RPAREN -> ^(LEXER_ACTION_CALL lexerCommandName lexerCommandExpr)
+ | lexerCommandName
+ ;
+
+lexerCommandExpr
+ : id
+ | INT
+ ;
+
+lexerCommandName
+ : id
+ | MODE ->ID[$MODE]
+ ;
+
+altList
+ : alternative (OR alternative)* -> alternative+
+ ;
+
+// An individual alt with an optional alt option like <assoc=right>
+alternative
+@init { paraphrases.push("matching alternative"); }
+@after {
+ paraphrases.pop();
+ Grammar.setNodeOptions($tree, $o.tree);
+}
+ : o=elementOptions?
+ ( e+=element+ -> ^(ALT<AltAST> elementOptions? $e+)
+ | -> ^(ALT<AltAST> elementOptions? EPSILON) // empty alt
+ )
+ ;
+
+element
+@init {
+ paraphrases.push("looking for rule element");
+ int m = input.mark();
+}
+@after { paraphrases.pop(); }
+ : labeledElement
+ ( ebnfSuffix -> ^( ebnfSuffix ^(BLOCK<BlockAST>[$labeledElement.start,"BLOCK"] ^(ALT<AltAST> labeledElement ) ))
+ | -> labeledElement
+ )
+ | atom
+ ( ebnfSuffix -> ^( ebnfSuffix ^(BLOCK<BlockAST>[$atom.start,"BLOCK"] ^(ALT<AltAST> atom) ) )
+ | -> atom
+ )
+ | ebnf
+ | actionElement
+ ;
+ catch [RecognitionException re] {
+ retval.tree = (GrammarAST)adaptor.errorNode(input, retval.start, input.LT(-1), re);
+ int ttype = input.get(input.range()).getType();
+ // look for anything that really belongs at the start of the rule minus the initial ID
+ if ( ttype==COLON || ttype==RETURNS || ttype==CATCH || ttype==FINALLY || ttype==AT ) {
+ RecognitionException missingSemi =
+ new v4ParserException("unterminated rule (missing ';') detected at '"+
+ input.LT(1).getText()+" "+input.LT(2).getText()+"'", input);
+ reportError(missingSemi);
+ if ( ttype==CATCH || ttype==FINALLY ) {
+ input.seek(input.range()); // ignore what's before rule trailer stuff
+ }
+ if ( ttype==RETURNS || ttype==AT ) { // scan back looking for ID of rule header
+ int p = input.index();
+ Token t = input.get(p);
+ while ( t.getType()!=RULE_REF && t.getType()!=TOKEN_REF ) {
+ p--;
+ t = input.get(p);
+ }
+ input.seek(p);
+ }
+ throw new ResyncToEndOfRuleBlock(); // make sure it goes back to rule block level to recover
+ }
+ reportError(re);
+ recover(input,re);
+ }
+
+actionElement
+@after {
+ GrammarAST options = (GrammarAST)$tree.getFirstChildWithType(ANTLRParser.ELEMENT_OPTIONS);
+ if ( options!=null ) {
+ Grammar.setNodeOptions($tree, options);
+ }
+}
+ : ACTION<ActionAST>
+ | ACTION elementOptions -> ^(ACTION<ActionAST> elementOptions)
+ | SEMPRED<PredAST>
+ | SEMPRED elementOptions -> ^(SEMPRED<PredAST> elementOptions)
+ ;
+
+labeledElement
+ : id (ass=ASSIGN|ass=PLUS_ASSIGN)
+ ( atom -> ^($ass id atom)
+ | block -> ^($ass id block)
+ )
+ ;
+
+// A block of gramamr structure optionally followed by standard EBNF
+// notation, or ANTLR specific notation. I.E. ? + ^ and so on
+ebnf
+ : block
+ // And now we see if we have any of the optional suffixs and rewrite
+ // the AST for this rule accordingly
+ ( blockSuffix -> ^(blockSuffix block)
+ | -> block
+ )
+ ;
+
+// The standard EBNF suffixes with additional components that make
+// sense only to ANTLR, in the context of a grammar block.
+blockSuffix
+ : ebnfSuffix // Standard EBNF
+ ;
+
+ebnfSuffix
+ : QUESTION nongreedy=QUESTION? -> OPTIONAL<OptionalBlockAST>[$start, $nongreedy]
+ | STAR nongreedy=QUESTION? -> CLOSURE<StarBlockAST>[$start, $nongreedy]
+ | PLUS nongreedy=QUESTION? -> POSITIVE_CLOSURE<PlusBlockAST>[$start, $nongreedy]
+ ;
+
+lexerAtom
+ : range
+ | terminal
+ | RULE_REF<RuleRefAST>
+ | notSet
+ | wildcard
+ | LEXER_CHAR_SET
+ ;
+
+atom
+ : // Qualified reference delegate.rule. This must be
+ // lexically contiguous (no spaces either side of the DOT)
+ // otherwise it is two references with a wildcard in between
+ // and not a qualified reference.
+ /*
+ {
+ input.LT(1).getCharPositionInLine()+input.LT(1).getText().length()==
+ input.LT(2).getCharPositionInLine() &&
+ input.LT(2).getCharPositionInLine()+1==input.LT(3).getCharPositionInLine()
+ }?
+ id DOT ruleref -> ^(DOT id ruleref)
+
+ |
+ */
+ range // Range x..y - only valid in lexers
+ | terminal
+ | ruleref
+ | notSet
+ | wildcard
+ ;
+ catch [RecognitionException re] { throw re; } // pass upwards to element
+
+wildcard
+@after {
+ GrammarAST options = (GrammarAST)$tree.getFirstChildWithType(ANTLRParser.ELEMENT_OPTIONS);
+ if ( options!=null ) {
+ Grammar.setNodeOptions($tree, options);
+ }
+}
+ : // Wildcard '.' means any character in a lexer, any
+ // token in parser and any node or subtree in a tree parser
+ // Because the terminal rule is allowed to be the node
+ // specification for the start of a tree rule, we must
+ // later check that wildcard was not used for that.
+ DOT elementOptions?
+ -> ^(WILDCARD<TerminalAST>[$DOT] elementOptions?)
+ ;
+
+// --------------------
+// Inverted element set
+//
+// A set of characters (in a lexer) or terminal tokens, if a parser,
+// that are then used to create the inverse set of them.
+notSet
+ : NOT setElement -> ^(NOT<NotAST>[$NOT] ^(SET<SetAST>[$setElement.start,"SET"] setElement))
+ | NOT blockSet -> ^(NOT<NotAST>[$NOT] blockSet)
+ ;
+
+blockSet
+@init {
+ Token t;
+ boolean ebnf = false;
+}
+ : LPAREN setElement (OR setElement)* RPAREN
+ -> ^(SET<SetAST>[$LPAREN,"SET"] setElement+ )
+ ;
+
+setElement
+ : TOKEN_REF<TerminalAST>^ elementOptions?
+ | STRING_LITERAL<TerminalAST>^ elementOptions?
+ | range
+ | LEXER_CHAR_SET
+ ;
+
+// -------------
+// Grammar Block
+//
+// Anywhere where an element is valid, the grammar may start a new block
+// of alts by surrounding that block with ( ). A new block may also have a set
+// of options, which apply only to that block.
+//
+block
+@after {
+GrammarAST options = (GrammarAST)$tree.getFirstChildWithType(ANTLRParser.OPTIONS);
+if ( options!=null ) {
+ Grammar.setNodeOptions($tree, options);
+}
+}
+ : LPAREN
+ ( optionsSpec? ra+=ruleAction* COLON )?
+ altList
+ RPAREN
+ -> ^(BLOCK<BlockAST>[$LPAREN,"BLOCK"] optionsSpec? $ra* altList )
+ ;
+
+// ----------------
+// Parser rule ref
+//
+// Reference to a parser rule with optional arguments and optional
+// directive to become the root node or ignore the tree produced
+//
+ruleref
+@after {
+GrammarAST options = (GrammarAST)$tree.getFirstChildWithType(ANTLRParser.ELEMENT_OPTIONS);
+if ( options!=null ) {
+ Grammar.setNodeOptions($tree, options);
+}
+}
+ : RULE_REF ARG_ACTION? elementOptions? -> ^(RULE_REF<RuleRefAST> ARG_ACTION<ActionAST>? elementOptions?)
+ ;
+ catch [RecognitionException re] { throw re; } // pass upwards to element
+
+// ---------------
+// Character Range
+//
+// Specifies a range of characters. Valid for lexer rules only, but
+// we do not check that here, the tree walkers shoudl do that.
+// Note also that the parser also allows through more than just
+// character literals so that we can produce a much nicer semantic
+// error about any abuse of the .. operator.
+//
+range
+ : STRING_LITERAL<TerminalAST> RANGE<RangeAST>^ STRING_LITERAL<TerminalAST>
+ ;
+
+terminal
+@after {
+GrammarAST options = (GrammarAST)$tree.getFirstChildWithType(ANTLRParser.ELEMENT_OPTIONS);
+if ( options!=null ) {
+ Grammar.setNodeOptions($tree, options);
+}
+}
+ : TOKEN_REF elementOptions? -> ^(TOKEN_REF<TerminalAST> elementOptions?)
+ | STRING_LITERAL elementOptions? -> ^(STRING_LITERAL<TerminalAST> elementOptions?)
+ ;
+
+// Terminals may be adorned with certain options when
+// reference in the grammar: TOK<,,,>
+elementOptions
+ : LT (elementOption (COMMA elementOption)*)? GT
+ -> ^(ELEMENT_OPTIONS[$LT,"ELEMENT_OPTIONS"] elementOption*)
+ ;
+
+// When used with elements we can specify what the tree node type can
+// be and also assign settings of various options (which we do not check here)
+elementOption
+ : // This format indicates the default element option
+ qid
+ | id ASSIGN^ optionValue
+ ;
+
+// The name of the grammar, and indeed some other grammar elements may
+// come through to the parser looking like a rule reference or a token
+// reference, hence this rule is used to pick up whichever it is and rewrite
+// it as a generic ID token.
+id
+@init { paraphrases.push("looking for an identifier"); }
+@after { paraphrases.pop(); }
+ : RULE_REF ->ID[$RULE_REF]
+ | TOKEN_REF ->ID[$TOKEN_REF]
+ ;
+
+qid
+@init { paraphrases.push("looking for a qualified identifier"); }
+@after { paraphrases.pop(); }
+ : id (DOT id)* -> ID[$qid.start, $text]
+ ;
+
+alternativeEntry : alternative EOF ; // allow gunit to call alternative and see EOF afterwards
+elementEntry : element EOF ;
+ruleEntry : rule EOF ;
+blockEntry : block EOF ;
diff --git a/tool/src/org/antlr/v4/parse/ATNBuilder.g b/tool/src/org/antlr/v4/parse/ATNBuilder.g
new file mode 100644
index 0000000..019f246
--- /dev/null
+++ b/tool/src/org/antlr/v4/parse/ATNBuilder.g
@@ -0,0 +1,214 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+tree grammar ATNBuilder;
+options {
+ language = Java;
+ tokenVocab = ANTLRParser;
+ ASTLabelType = GrammarAST;
+// filter = true;
+}
+
+// Include the copyright in this source and also the generated source
+@header {
+/*
+ [The "BSD license"]
+ Copyright (c) 2010 Terence Parr
+ All rights reserved.
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+package org.antlr.v4.parse;
+import org.antlr.v4.tool.*;
+import org.antlr.v4.tool.ast.*;
+import org.antlr.v4.automata.ATNFactory;
+}
+
+@members {
+ ATNFactory factory;
+ public ATNBuilder(TreeNodeStream input, ATNFactory factory) {
+ this(input);
+ this.factory = factory;
+ }
+}
+
+dummy : block[null] ; // avoid error about no start rule
+
+ruleBlock[GrammarAST ebnfRoot] returns [ATNFactory.Handle p]
+@init {
+ List<ATNFactory.Handle> alts = new ArrayList<ATNFactory.Handle>();
+ int alt = 1;
+ factory.setCurrentOuterAlt(alt);
+}
+ : ^(BLOCK
+ (^(OPTIONS .*))?
+ ( a=alternative
+ {alts.add($a.p); factory.setCurrentOuterAlt(++alt);}
+ )+
+ )
+ {$p = factory.block((BlockAST)$BLOCK, ebnfRoot, alts);}
+ ;
+
+block[GrammarAST ebnfRoot] returns [ATNFactory.Handle p]
+@init {List<ATNFactory.Handle> alts = new ArrayList<ATNFactory.Handle>();}
+ : ^(BLOCK (^(OPTIONS .*))? (a=alternative {alts.add($a.p);})+)
+ {$p = factory.block((BlockAST)$BLOCK, ebnfRoot, alts);}
+ ;
+
+alternative returns [ATNFactory.Handle p]
+@init {List<ATNFactory.Handle> els = new ArrayList<ATNFactory.Handle>();}
+ : ^(LEXER_ALT_ACTION a=alternative lexerCommands)
+ {$p = factory.lexerAltCommands($a.p,$lexerCommands.p);}
+ | ^(ALT elementOptions? EPSILON) {$p = factory.epsilon($EPSILON);}
+ | ^(ALT elementOptions? (e=element {els.add($e.p);})+) {$p = factory.alt(els);}
+ ;
+
+lexerCommands returns [ATNFactory.Handle p]
+@init {List<ATNFactory.Handle> cmds = new ArrayList<ATNFactory.Handle>();}
+ : (c=lexerCommand {if ($c.cmd != null) cmds.add($c.cmd);})+
+ {
+ $p = factory.alt(cmds);
+ }
+ ;
+
+lexerCommand returns [ATNFactory.Handle cmd]
+ : ^(LEXER_ACTION_CALL ID lexerCommandExpr)
+ {$cmd = factory.lexerCallCommand($ID, $lexerCommandExpr.start);}
+ | ID
+ {$cmd = factory.lexerCommand($ID);}
+ ;
+
+lexerCommandExpr
+ : ID
+ | INT
+ ;
+
+element returns [ATNFactory.Handle p]
+ : labeledElement {$p = $labeledElement.p;}
+ | atom {$p = $atom.p;}
+ | subrule {$p = $subrule.p;}
+ | ACTION {$p = factory.action((ActionAST)$ACTION);}
+ | SEMPRED {$p = factory.sempred((PredAST)$SEMPRED);}
+ | ^(ACTION .) {$p = factory.action((ActionAST)$ACTION);}
+ | ^(SEMPRED .) {$p = factory.sempred((PredAST)$SEMPRED);}
+ | ^(NOT b=blockSet[true]) {$p = $b.p;}
+ | LEXER_CHAR_SET {$p = factory.charSetLiteral($start);}
+ ;
+
+astOperand returns [ATNFactory.Handle p]
+ : atom {$p = $atom.p;}
+ | ^(NOT blockSet[true]) {$p = $blockSet.p;}
+ ;
+
+labeledElement returns [ATNFactory.Handle p]
+ : ^(ASSIGN ID element) {$p = factory.label($element.p);}
+ | ^(PLUS_ASSIGN ID element) {$p = factory.listLabel($element.p);}
+ ;
+
+subrule returns [ATNFactory.Handle p]
+ : ^(OPTIONAL block[$start]) {$p = $block.p;}
+ | ^(CLOSURE block[$start]) {$p = $block.p;}
+ | ^(POSITIVE_CLOSURE block[$start]) {$p = $block.p;}
+ | block[null] {$p = $block.p;}
+ ;
+
+blockSet[boolean invert] returns [ATNFactory.Handle p]
+@init {List<GrammarAST> alts = new ArrayList<GrammarAST>();}
+ : ^(SET (setElement {alts.add($setElement.start);})+) {$p = factory.set($start, alts, $invert);}
+ ;
+
+/** Don't combine with atom otherwise it will build spurious ATN nodes */
+setElement
+ : ^(STRING_LITERAL .)
+ | ^(TOKEN_REF .)
+ | STRING_LITERAL
+ | TOKEN_REF
+ | ^(RANGE a=STRING_LITERAL b=STRING_LITERAL)
+ | LEXER_CHAR_SET
+ ;
+
+atom returns [ATNFactory.Handle p]
+ : range {$p = $range.p;}
+ | ^(DOT ID terminal) {$p = $terminal.p;}
+ | ^(DOT ID ruleref) {$p = $ruleref.p;}
+ | ^(WILDCARD .) {$p = factory.wildcard($start);}
+ | WILDCARD {$p = factory.wildcard($start);}
+ | blockSet[false] {$p = $blockSet.p;}
+ | terminal {$p = $terminal.p;}
+ | ruleref {$p = $ruleref.p;}
+ ;
+
+ruleref returns [ATNFactory.Handle p]
+ : ^(RULE_REF ARG_ACTION? ^(ELEMENT_OPTIONS .*)) {$p = factory.ruleRef($RULE_REF);}
+ | ^(RULE_REF ARG_ACTION?) {$p = factory.ruleRef($RULE_REF);}
+ | RULE_REF {$p = factory.ruleRef($RULE_REF);}
+ ;
+
+range returns [ATNFactory.Handle p]
+ : ^(RANGE a=STRING_LITERAL b=STRING_LITERAL) {$p = factory.range($a,$b);}
+ ;
+
+terminal returns [ATNFactory.Handle p]
+ : ^(STRING_LITERAL .) {$p = factory.stringLiteral((TerminalAST)$start);}
+ | STRING_LITERAL {$p = factory.stringLiteral((TerminalAST)$start);}
+ | ^(TOKEN_REF ARG_ACTION .) {$p = factory.tokenRef((TerminalAST)$start);}
+ | ^(TOKEN_REF .) {$p = factory.tokenRef((TerminalAST)$start);}
+ | TOKEN_REF {$p = factory.tokenRef((TerminalAST)$start);}
+ ;
+
+elementOptions
+ : ^(ELEMENT_OPTIONS elementOption*)
+ ;
+
+elementOption
+ : ID
+ | ^(ASSIGN ID ID)
+ | ^(ASSIGN ID STRING_LITERAL)
+ | ^(ASSIGN ID ACTION)
+ | ^(ASSIGN ID INT)
+ ;
diff --git a/tool/src/org/antlr/v4/parse/ActionSplitter.g b/tool/src/org/antlr/v4/parse/ActionSplitter.g
new file mode 100644
index 0000000..5feeb95
--- /dev/null
+++ b/tool/src/org/antlr/v4/parse/ActionSplitter.g
@@ -0,0 +1,125 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+lexer grammar ActionSplitter;
+
+options { filter=true; }
+
+@header {
+package org.antlr.v4.parse;
+import org.antlr.v4.tool.*;
+import org.antlr.v4.tool.ast.*;
+}
+
+@members {
+ActionSplitterListener delegate;
+
+public ActionSplitter(CharStream input, ActionSplitterListener delegate) {
+ this(input, new RecognizerSharedState());
+ this.delegate = delegate;
+}
+
+/** force filtering (and return tokens). triggers all above actions. */
+public List<Token> getActionTokens() {
+ List<Token> chunks = new ArrayList<Token>();
+ Token t = nextToken();
+ while ( t.getType()!=Token.EOF ) {
+ chunks.add(t);
+ t = nextToken();
+ }
+ return chunks;
+}
+
+private boolean isIDStartChar(int c) {
+ return c == '_' || Character.isLetter(c);
+}
+}
+
+// ignore comments right away
+
+COMMENT
+ : '/*' ( options {greedy=false;} : . )* '*/' {delegate.text($text);}
+ ;
+
+LINE_COMMENT
+ : '//' ~('\n'|'\r')* '\r'? '\n' {delegate.text($text);}
+ ;
+
+SET_NONLOCAL_ATTR
+ : '$' x=ID '::' y=ID WS? '=' expr=ATTR_VALUE_EXPR ';'
+ {
+ delegate.setNonLocalAttr($text, $x, $y, $expr);
+ }
+ ;
+
+NONLOCAL_ATTR
+ : '$' x=ID '::' y=ID {delegate.nonLocalAttr($text, $x, $y);}
+ ;
+
+QUALIFIED_ATTR
+ : '$' x=ID '.' y=ID {input.LA(1)!='('}? {delegate.qualifiedAttr($text, $x, $y);}
+ ;
+
+SET_ATTR
+ : '$' x=ID WS? '=' expr=ATTR_VALUE_EXPR ';'
+ {
+ delegate.setAttr($text, $x, $expr);
+ }
+ ;
+
+ATTR
+ : '$' x=ID {delegate.attr($text, $x);}
+ ;
+
+// Anything else is just random text
+TEXT
+@init {StringBuilder buf = new StringBuilder();}
+@after {delegate.text(buf.toString());}
+ : ( c=~('\\'| '$') {buf.append((char)$c);}
+ | '\\$' {buf.append('$');}
+ | '\\' c=~('$') {buf.append('\\').append((char)$c);}
+ | {!isIDStartChar(input.LA(2))}? => '$' {buf.append('$');}
+ )+
+ ;
+
+fragment
+ID : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')*
+ ;
+
+/** Don't allow an = as first char to prevent $x == 3; kind of stuff. */
+fragment
+ATTR_VALUE_EXPR
+ : ~'=' (~';')*
+ ;
+
+fragment
+WS : (' '|'\t'|'\n'|'\r')+
+ ;
+
diff --git a/tool/src/org/antlr/v4/parse/ActionSplitterListener.java b/tool/src/org/antlr/v4/parse/ActionSplitterListener.java
new file mode 100644
index 0000000..0e793b7
--- /dev/null
+++ b/tool/src/org/antlr/v4/parse/ActionSplitterListener.java
@@ -0,0 +1,45 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.parse;
+
+import org.antlr.runtime.Token;
+
+/** */
+public interface ActionSplitterListener {
+ void qualifiedAttr(String expr, Token x, Token y);
+ void setAttr(String expr, Token x, Token rhs);
+ void attr(String expr, Token x);
+
+ void setNonLocalAttr(String expr, Token x, Token y, Token rhs);
+ void nonLocalAttr(String expr, Token x, Token y);
+
+ void text(String text);
+}
diff --git a/tool/src/org/antlr/v4/parse/BlockSetTransformer.g b/tool/src/org/antlr/v4/parse/BlockSetTransformer.g
new file mode 100644
index 0000000..2233b30
--- /dev/null
+++ b/tool/src/org/antlr/v4/parse/BlockSetTransformer.g
@@ -0,0 +1,129 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+tree grammar BlockSetTransformer;
+options {
+ language = Java;
+ tokenVocab = ANTLRParser;
+ ASTLabelType = GrammarAST;
+ output = AST;
+ filter = true;
+}
+
+@header {
+package org.antlr.v4.parse;
+import org.antlr.v4.misc.Utils;
+import org.antlr.v4.misc.*;
+import org.antlr.v4.tool.*;
+import org.antlr.v4.tool.ast.*;
+import java.util.List;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.ArrayList;
+import org.antlr.v4.runtime.misc.IntervalSet;
+}
+
+@members {
+public String currentRuleName;
+public GrammarAST currentAlt;
+public Grammar g;
+public BlockSetTransformer(TreeNodeStream input, Grammar g) {
+ this(input, new RecognizerSharedState());
+ this.g = g;
+}
+}
+
+topdown
+ : ^(RULE (id=TOKEN_REF|id=RULE_REF) {currentRuleName=$id.text;} .+)
+ | setAlt
+ | ebnfBlockSet
+ | blockSet
+ ;
+
+setAlt
+ : {inContext("RULE BLOCK")}?
+ ALT {currentAlt = $start;}
+ ;
+
+// (BLOCK (ALT (+ (BLOCK (ALT INT) (ALT ID)))))
+ebnfBlockSet
+@after {
+ GrammarTransformPipeline.setGrammarPtr(g, $tree);
+}
+ : ^(ebnfSuffix blockSet) -> ^(ebnfSuffix ^(BLOCK<BlockAST> ^(ALT<AltAST> blockSet)))
+ ;
+
+ebnfSuffix
+@after {$tree = (GrammarAST)adaptor.dupNode($start);}
+ : OPTIONAL
+ | CLOSURE
+ | POSITIVE_CLOSURE
+ ;
+
+blockSet
+@init {
+boolean inLexer = Grammar.isTokenName(currentRuleName);
+}
+@after {
+ GrammarTransformPipeline.setGrammarPtr(g, $tree);
+}
+ : {inContext("RULE")}? // top-level: rule block and > 1 alt
+ ^(BLOCK ^(alt=ALT elementOptions? {((AltAST)$alt).altLabel==null}? setElement[inLexer]) ( ^(ALT elementOptions? setElement[inLexer]) )+)
+ -> ^(BLOCK<BlockAST>[$BLOCK.token] ^(ALT<AltAST>[$BLOCK.token,"ALT"] ^(SET[$BLOCK.token, "SET"] setElement+)))
+ | {!inContext("RULE")}? // if not rule block and > 1 alt
+ ^(BLOCK ^(ALT elementOptions? setElement[inLexer]) ( ^(ALT elementOptions? setElement[inLexer]) )+)
+ -> ^(SET[$BLOCK.token, "SET"] setElement+)
+ ;
+
+setElement[boolean inLexer]
+@after {
+ GrammarTransformPipeline.setGrammarPtr(g, $tree);
+}
+ : ( ^(a=STRING_LITERAL elementOptions) {!inLexer || CharSupport.getCharValueFromGrammarCharLiteral($a.getText())!=-1}?
+ | a=STRING_LITERAL {!inLexer || CharSupport.getCharValueFromGrammarCharLiteral($a.getText())!=-1}?
+ | {!inLexer}?=> ^(TOKEN_REF elementOptions)
+ | {!inLexer}?=> TOKEN_REF
+ | {inLexer}?=> ^(RANGE a=STRING_LITERAL b=STRING_LITERAL)
+ {CharSupport.getCharValueFromGrammarCharLiteral($a.getText())!=-1 &&
+ CharSupport.getCharValueFromGrammarCharLiteral($b.getText())!=-1}?
+ )
+ ;
+
+elementOptions
+ : ^(ELEMENT_OPTIONS elementOption*)
+ ;
+
+elementOption
+ : ID
+ | ^(ASSIGN id=ID v=ID)
+ | ^(ASSIGN ID v=STRING_LITERAL)
+ | ^(ASSIGN ID v=ACTION)
+ | ^(ASSIGN ID v=INT)
+ ;
diff --git a/tool/src/org/antlr/v4/parse/GrammarASTAdaptor.java b/tool/src/org/antlr/v4/parse/GrammarASTAdaptor.java
new file mode 100644
index 0000000..e6a0ec3
--- /dev/null
+++ b/tool/src/org/antlr/v4/parse/GrammarASTAdaptor.java
@@ -0,0 +1,83 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.parse;
+
+import org.antlr.runtime.CommonToken;
+import org.antlr.runtime.Token;
+import org.antlr.runtime.tree.CommonTreeAdaptor;
+import org.antlr.v4.tool.ast.GrammarAST;
+import org.antlr.v4.tool.ast.GrammarASTErrorNode;
+import org.antlr.v4.tool.ast.RuleAST;
+import org.antlr.v4.tool.ast.TerminalAST;
+
+public class GrammarASTAdaptor extends CommonTreeAdaptor {
+ org.antlr.runtime.CharStream input; // where we can find chars ref'd by tokens in tree
+ public GrammarASTAdaptor() { }
+ public GrammarASTAdaptor(org.antlr.runtime.CharStream input) { this.input = input; }
+
+ @Override
+ public Object create(Token token) {
+ return new GrammarAST(token);
+ }
+
+ @Override
+ /** Make sure even imaginary nodes know the input stream */
+ public Object create(int tokenType, String text) {
+ GrammarAST t;
+ if ( tokenType==ANTLRParser.RULE ) {
+ // needed by TreeWizard to make RULE tree
+ t = new RuleAST(new CommonToken(tokenType, text));
+ }
+ else if ( tokenType==ANTLRParser.STRING_LITERAL ) {
+ // implicit lexer construction done with wizard; needs this node type
+ // whereas grammar ANTLRParser.g can use token option to spec node type
+ t = new TerminalAST(new CommonToken(tokenType, text));
+ }
+ else {
+ t = (GrammarAST)super.create(tokenType, text);
+ }
+ t.token.setInputStream(input);
+ return t;
+ }
+
+ @Override
+ public Object dupNode(Object t) {
+ if ( t==null ) return null;
+ return ((GrammarAST)t).dupNode(); //create(((GrammarAST)t).token);
+ }
+
+ @Override
+ public Object errorNode(org.antlr.runtime.TokenStream input, org.antlr.runtime.Token start, org.antlr.runtime.Token stop,
+ org.antlr.runtime.RecognitionException e)
+ {
+ return new GrammarASTErrorNode(input, start, stop, e);
+ }
+}
diff --git a/tool/src/org/antlr/v4/parse/GrammarToken.java b/tool/src/org/antlr/v4/parse/GrammarToken.java
new file mode 100644
index 0000000..4d849bf
--- /dev/null
+++ b/tool/src/org/antlr/v4/parse/GrammarToken.java
@@ -0,0 +1,98 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2014 Terence Parr
+ * Copyright (c) 2014 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.parse;
+
+import org.antlr.runtime.CommonToken;
+import org.antlr.runtime.Token;
+import org.antlr.v4.tool.Grammar;
+
+/** A CommonToken that can also track it's original location,
+ * derived from options on the element ref like BEGIN<line=34,...>.
+ */
+public class GrammarToken extends CommonToken {
+ public Grammar g;
+ public int originalTokenIndex = -1;
+
+ public GrammarToken(Grammar g, Token oldToken) {
+ super(oldToken);
+ this.g = g;
+ }
+
+ @Override
+ public int getCharPositionInLine() {
+ if ( originalTokenIndex>=0 ) return g.originalTokenStream.get(originalTokenIndex).getCharPositionInLine();
+ return super.getCharPositionInLine();
+ }
+
+ @Override
+ public int getLine() {
+ if ( originalTokenIndex>=0 ) return g.originalTokenStream.get(originalTokenIndex).getLine();
+ return super.getLine();
+ }
+
+ @Override
+ public int getTokenIndex() {
+ return originalTokenIndex;
+ }
+
+ @Override
+ public int getStartIndex() {
+ if ( originalTokenIndex>=0 ) {
+ return ((CommonToken)g.originalTokenStream.get(originalTokenIndex)).getStartIndex();
+ }
+ return super.getStartIndex();
+ }
+
+ @Override
+ public int getStopIndex() {
+ int n = super.getStopIndex() - super.getStartIndex() + 1;
+ return getStartIndex() + n - 1;
+ }
+
+ @Override
+ public String toString() {
+ String channelStr = "";
+ if ( channel>0 ) {
+ channelStr=",channel="+channel;
+ }
+ String txt = getText();
+ if ( txt!=null ) {
+ txt = txt.replaceAll("\n","\\\\n");
+ txt = txt.replaceAll("\r","\\\\r");
+ txt = txt.replaceAll("\t","\\\\t");
+ }
+ else {
+ txt = "<no text>";
+ }
+ return "[@"+getTokenIndex()+","+getStartIndex()+":"+getStopIndex()+
+ "='"+txt+"',<"+getType()+">"+channelStr+","+getLine()+":"+getCharPositionInLine()+"]";
+ }
+}
diff --git a/tool/src/org/antlr/v4/parse/GrammarTreeVisitor.g b/tool/src/org/antlr/v4/parse/GrammarTreeVisitor.g
new file mode 100644
index 0000000..9c8b1be
--- /dev/null
+++ b/tool/src/org/antlr/v4/parse/GrammarTreeVisitor.g
@@ -0,0 +1,1033 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** The definitive ANTLR v3 tree grammar to walk/visit ANTLR v4 grammars.
+ * Parses trees created by ANTLRParser.g.
+ *
+ * Rather than have multiple tree grammars, one for each visit, I'm
+ * creating this generic visitor that knows about context. All of the
+ * boilerplate pattern recognition is done here. Then, subclasses can
+ * override the methods they care about. This prevents a lot of the same
+ * context tracking stuff like "set current alternative for current
+ * rule node" that is repeated in lots of tree filters.
+ */
+tree grammar GrammarTreeVisitor;
+options {
+ language = Java;
+ tokenVocab = ANTLRParser;
+ ASTLabelType = GrammarAST;
+}
+
+// Include the copyright in this source and also the generated source
+@header {
+/*
+ [The "BSD license"]
+ Copyright (c) 2011 Terence Parr
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.v4.parse;
+import org.antlr.v4.Tool;
+import org.antlr.v4.tool.*;
+import org.antlr.v4.tool.ast.*;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+}
+
+@members {
+public String grammarName;
+public GrammarAST currentRuleAST;
+public String currentModeName = LexerGrammar.DEFAULT_MODE_NAME;
+public String currentRuleName;
+public GrammarAST currentOuterAltRoot;
+public int currentOuterAltNumber = 1; // 1..n
+public int rewriteEBNFLevel = 0;
+
+public GrammarTreeVisitor() { this(null); }
+
+// Should be abstract but can't make gen'd parser abstract;
+// subclasses should implement else everything goes to stderr!
+public ErrorManager getErrorManager() { return null; }
+
+public void visitGrammar(GrammarAST t) { visit(t, "grammarSpec"); }
+public void visit(GrammarAST t, String ruleName) {
+ CommonTreeNodeStream nodes = new CommonTreeNodeStream(new GrammarASTAdaptor(), t);
+ setTreeNodeStream(nodes);
+ try {
+ Method m = getClass().getMethod(ruleName);
+ m.invoke(this);
+ }
+ catch (Throwable e) {
+ ErrorManager errMgr = getErrorManager();
+ if ( e instanceof InvocationTargetException ) {
+ e = e.getCause();
+ }
+ //e.printStackTrace(System.err);
+ if ( errMgr==null ) {
+ System.err.println("can't find rule "+ruleName+
+ " or tree structure error: "+t.toStringTree()
+ );
+ e.printStackTrace(System.err);
+ }
+ else errMgr.toolError(ErrorType.INTERNAL_ERROR, e);
+ }
+}
+
+public void discoverGrammar(GrammarRootAST root, GrammarAST ID) { }
+public void finishPrequels(GrammarAST firstPrequel) { }
+public void finishGrammar(GrammarRootAST root, GrammarAST ID) { }
+
+public void grammarOption(GrammarAST ID, GrammarAST valueAST) { }
+public void ruleOption(GrammarAST ID, GrammarAST valueAST) { }
+public void blockOption(GrammarAST ID, GrammarAST valueAST) { }
+public void defineToken(GrammarAST ID) { }
+public void defineChannel(GrammarAST ID) { }
+public void globalNamedAction(GrammarAST scope, GrammarAST ID, ActionAST action) { }
+public void importGrammar(GrammarAST label, GrammarAST ID) { }
+
+public void modeDef(GrammarAST m, GrammarAST ID) { }
+
+public void discoverRules(GrammarAST rules) { }
+public void finishRules(GrammarAST rule) { }
+public void discoverRule(RuleAST rule, GrammarAST ID, List<GrammarAST> modifiers,
+ ActionAST arg, ActionAST returns, GrammarAST thrws,
+ GrammarAST options, ActionAST locals,
+ List<GrammarAST> actions,
+ GrammarAST block) { }
+public void finishRule(RuleAST rule, GrammarAST ID, GrammarAST block) { }
+public void discoverLexerRule(RuleAST rule, GrammarAST ID, List<GrammarAST> modifiers,
+ GrammarAST block) { }
+public void finishLexerRule(RuleAST rule, GrammarAST ID, GrammarAST block) { }
+public void ruleCatch(GrammarAST arg, ActionAST action) { }
+public void finallyAction(ActionAST action) { }
+public void discoverOuterAlt(AltAST alt) { }
+public void finishOuterAlt(AltAST alt) { }
+public void discoverAlt(AltAST alt) { }
+public void finishAlt(AltAST alt) { }
+
+public void ruleRef(GrammarAST ref, ActionAST arg) { }
+public void tokenRef(TerminalAST ref) { }
+public void elementOption(GrammarASTWithOptions t, GrammarAST ID, GrammarAST valueAST) { }
+public void stringRef(TerminalAST ref) { }
+public void wildcardRef(GrammarAST ref) { }
+public void actionInAlt(ActionAST action) { }
+public void sempredInAlt(PredAST pred) { }
+public void label(GrammarAST op, GrammarAST ID, GrammarAST element) { }
+public void lexerCallCommand(int outerAltNumber, GrammarAST ID, GrammarAST arg) { }
+public void lexerCommand(int outerAltNumber, GrammarAST ID) { }
+
+protected void enterGrammarSpec(GrammarAST tree) { }
+protected void exitGrammarSpec(GrammarAST tree) { }
+
+protected void enterPrequelConstructs(GrammarAST tree) { }
+protected void exitPrequelConstructs(GrammarAST tree) { }
+
+protected void enterPrequelConstruct(GrammarAST tree) { }
+protected void exitPrequelConstruct(GrammarAST tree) { }
+
+protected void enterOptionsSpec(GrammarAST tree) { }
+protected void exitOptionsSpec(GrammarAST tree) { }
+
+protected void enterOption(GrammarAST tree) { }
+protected void exitOption(GrammarAST tree) { }
+
+protected void enterOptionValue(GrammarAST tree) { }
+protected void exitOptionValue(GrammarAST tree) { }
+
+protected void enterDelegateGrammars(GrammarAST tree) { }
+protected void exitDelegateGrammars(GrammarAST tree) { }
+
+protected void enterDelegateGrammar(GrammarAST tree) { }
+protected void exitDelegateGrammar(GrammarAST tree) { }
+
+protected void enterTokensSpec(GrammarAST tree) { }
+protected void exitTokensSpec(GrammarAST tree) { }
+
+protected void enterTokenSpec(GrammarAST tree) { }
+protected void exitTokenSpec(GrammarAST tree) { }
+
+protected void enterChannelsSpec(GrammarAST tree) { }
+protected void exitChannelsSpec(GrammarAST tree) { }
+
+protected void enterChannelSpec(GrammarAST tree) { }
+protected void exitChannelSpec(GrammarAST tree) { }
+
+protected void enterAction(GrammarAST tree) { }
+protected void exitAction(GrammarAST tree) { }
+
+protected void enterRules(GrammarAST tree) { }
+protected void exitRules(GrammarAST tree) { }
+
+protected void enterMode(GrammarAST tree) { }
+protected void exitMode(GrammarAST tree) { }
+
+protected void enterLexerRule(GrammarAST tree) { }
+protected void exitLexerRule(GrammarAST tree) { }
+
+protected void enterRule(GrammarAST tree) { }
+protected void exitRule(GrammarAST tree) { }
+
+protected void enterExceptionGroup(GrammarAST tree) { }
+protected void exitExceptionGroup(GrammarAST tree) { }
+
+protected void enterExceptionHandler(GrammarAST tree) { }
+protected void exitExceptionHandler(GrammarAST tree) { }
+
+protected void enterFinallyClause(GrammarAST tree) { }
+protected void exitFinallyClause(GrammarAST tree) { }
+
+protected void enterLocals(GrammarAST tree) { }
+protected void exitLocals(GrammarAST tree) { }
+
+protected void enterRuleReturns(GrammarAST tree) { }
+protected void exitRuleReturns(GrammarAST tree) { }
+
+protected void enterThrowsSpec(GrammarAST tree) { }
+protected void exitThrowsSpec(GrammarAST tree) { }
+
+protected void enterRuleAction(GrammarAST tree) { }
+protected void exitRuleAction(GrammarAST tree) { }
+
+protected void enterRuleModifier(GrammarAST tree) { }
+protected void exitRuleModifier(GrammarAST tree) { }
+
+protected void enterLexerRuleBlock(GrammarAST tree) { }
+protected void exitLexerRuleBlock(GrammarAST tree) { }
+
+protected void enterRuleBlock(GrammarAST tree) { }
+protected void exitRuleBlock(GrammarAST tree) { }
+
+protected void enterLexerOuterAlternative(AltAST tree) { }
+protected void exitLexerOuterAlternative(AltAST tree) { }
+
+protected void enterOuterAlternative(AltAST tree) { }
+protected void exitOuterAlternative(AltAST tree) { }
+
+protected void enterLexerAlternative(GrammarAST tree) { }
+protected void exitLexerAlternative(GrammarAST tree) { }
+
+protected void enterLexerElements(GrammarAST tree) { }
+protected void exitLexerElements(GrammarAST tree) { }
+
+protected void enterLexerElement(GrammarAST tree) { }
+protected void exitLexerElement(GrammarAST tree) { }
+
+protected void enterLabeledLexerElement(GrammarAST tree) { }
+protected void exitLabeledLexerElement(GrammarAST tree) { }
+
+protected void enterLexerBlock(GrammarAST tree) { }
+protected void exitLexerBlock(GrammarAST tree) { }
+
+protected void enterLexerAtom(GrammarAST tree) { }
+protected void exitLexerAtom(GrammarAST tree) { }
+
+protected void enterActionElement(GrammarAST tree) { }
+protected void exitActionElement(GrammarAST tree) { }
+
+protected void enterAlternative(AltAST tree) { }
+protected void exitAlternative(AltAST tree) { }
+
+protected void enterLexerCommand(GrammarAST tree) { }
+protected void exitLexerCommand(GrammarAST tree) { }
+
+protected void enterLexerCommandExpr(GrammarAST tree) { }
+protected void exitLexerCommandExpr(GrammarAST tree) { }
+
+protected void enterElement(GrammarAST tree) { }
+protected void exitElement(GrammarAST tree) { }
+
+protected void enterAstOperand(GrammarAST tree) { }
+protected void exitAstOperand(GrammarAST tree) { }
+
+protected void enterLabeledElement(GrammarAST tree) { }
+protected void exitLabeledElement(GrammarAST tree) { }
+
+protected void enterSubrule(GrammarAST tree) { }
+protected void exitSubrule(GrammarAST tree) { }
+
+protected void enterLexerSubrule(GrammarAST tree) { }
+protected void exitLexerSubrule(GrammarAST tree) { }
+
+protected void enterBlockSuffix(GrammarAST tree) { }
+protected void exitBlockSuffix(GrammarAST tree) { }
+
+protected void enterEbnfSuffix(GrammarAST tree) { }
+protected void exitEbnfSuffix(GrammarAST tree) { }
+
+protected void enterAtom(GrammarAST tree) { }
+protected void exitAtom(GrammarAST tree) { }
+
+protected void enterBlockSet(GrammarAST tree) { }
+protected void exitBlockSet(GrammarAST tree) { }
+
+protected void enterSetElement(GrammarAST tree) { }
+protected void exitSetElement(GrammarAST tree) { }
+
+protected void enterBlock(GrammarAST tree) { }
+protected void exitBlock(GrammarAST tree) { }
+
+protected void enterRuleref(GrammarAST tree) { }
+protected void exitRuleref(GrammarAST tree) { }
+
+protected void enterRange(GrammarAST tree) { }
+protected void exitRange(GrammarAST tree) { }
+
+protected void enterTerminal(GrammarAST tree) { }
+protected void exitTerminal(GrammarAST tree) { }
+
+protected void enterElementOptions(GrammarAST tree) { }
+protected void exitElementOptions(GrammarAST tree) { }
+
+protected void enterElementOption(GrammarAST tree) { }
+protected void exitElementOption(GrammarAST tree) { }
+
+ @Override
+ public void traceIn(String ruleName, int ruleIndex) {
+ System.err.println("enter "+ruleName+": "+input.LT(1));
+ }
+
+ @Override
+ public void traceOut(String ruleName, int ruleIndex) {
+ System.err.println("exit "+ruleName+": "+input.LT(1));
+ }
+}
+
+grammarSpec
+@init {
+ enterGrammarSpec($start);
+}
+@after {
+ exitGrammarSpec($start);
+}
+ : ^( GRAMMAR ID {grammarName=$ID.text;}
+ {discoverGrammar((GrammarRootAST)$GRAMMAR, $ID);}
+ prequelConstructs
+ {finishPrequels($prequelConstructs.firstOne);}
+ rules mode*
+ {finishGrammar((GrammarRootAST)$GRAMMAR, $ID);}
+ )
+ ;
+
+prequelConstructs returns [GrammarAST firstOne=null]
+@init {
+ enterPrequelConstructs($start);
+}
+@after {
+ exitPrequelConstructs($start);
+}
+ : {$firstOne=$start;} prequelConstruct+
+ |
+ ;
+
+prequelConstruct
+@init {
+ enterPrequelConstructs($start);
+}
+@after {
+ exitPrequelConstructs($start);
+}
+ : optionsSpec
+ | delegateGrammars
+ | tokensSpec
+ | channelsSpec
+ | action
+ ;
+
+optionsSpec
+@init {
+ enterOptionsSpec($start);
+}
+@after {
+ exitOptionsSpec($start);
+}
+ : ^(OPTIONS option*)
+ ;
+
+option
+@init {
+ enterOption($start);
+ boolean rule = inContext("RULE ...");
+ boolean block = inContext("BLOCK ...");
+}
+@after {
+ exitOption($start);
+}
+ : ^(a=ASSIGN ID v=optionValue)
+ {
+ if ( block ) blockOption($ID, $v.start); // most specific first
+ else if ( rule ) ruleOption($ID, $v.start);
+ else grammarOption($ID, $v.start);
+ }
+ ;
+
+optionValue returns [String v]
+@init {
+ enterOptionValue($start);
+ $v = $start.token.getText();
+}
+@after {
+ exitOptionValue($start);
+}
+ : ID
+ | STRING_LITERAL
+ | INT
+ ;
+
+delegateGrammars
+@init {
+ enterDelegateGrammars($start);
+}
+@after {
+ exitDelegateGrammars($start);
+}
+ : ^(IMPORT delegateGrammar+)
+ ;
+
+delegateGrammar
+@init {
+ enterDelegateGrammar($start);
+}
+@after {
+ exitDelegateGrammar($start);
+}
+ : ^(ASSIGN label=ID id=ID) {importGrammar($label, $id);}
+ | id=ID {importGrammar(null, $id);}
+ ;
+
+tokensSpec
+@init {
+ enterTokensSpec($start);
+}
+@after {
+ exitTokensSpec($start);
+}
+ : ^(TOKENS_SPEC tokenSpec+)
+ ;
+
+tokenSpec
+@init {
+ enterTokenSpec($start);
+}
+@after {
+ exitTokenSpec($start);
+}
+ : ID {defineToken($ID);}
+ ;
+
+channelsSpec
+@init {
+ enterChannelsSpec($start);
+}
+@after {
+ exitChannelsSpec($start);
+}
+ : ^(CHANNELS channelSpec+)
+ ;
+
+channelSpec
+@init {
+ enterChannelSpec($start);
+}
+@after {
+ exitChannelSpec($start);
+}
+ : ID {defineChannel($ID);}
+ ;
+
+action
+@init {
+ enterAction($start);
+}
+@after {
+ exitAction($start);
+}
+ : ^(AT sc=ID? name=ID ACTION) {globalNamedAction($sc, $name, (ActionAST)$ACTION);}
+ ;
+
+rules
+@init {
+ enterRules($start);
+}
+@after {
+ exitRules($start);
+}
+ : ^(RULES {discoverRules($RULES);} (rule|lexerRule)* {finishRules($RULES);})
+ ;
+
+mode
+@init {
+ enterMode($start);
+}
+@after {
+ exitMode($start);
+}
+ : ^( MODE ID {currentModeName=$ID.text; modeDef($MODE, $ID);} lexerRule* )
+ ;
+
+lexerRule
+@init {
+ enterLexerRule($start);
+ List<GrammarAST> mods = new ArrayList<GrammarAST>();
+ currentOuterAltNumber=0;
+}
+@after {
+ exitLexerRule($start);
+}
+ : ^( RULE TOKEN_REF
+ {currentRuleName=$TOKEN_REF.text; currentRuleAST=$RULE;}
+ (^(RULEMODIFIERS m=FRAGMENT {mods.add($m);}))?
+ {discoverLexerRule((RuleAST)$RULE, $TOKEN_REF, mods, (GrammarAST)input.LT(1));}
+ lexerRuleBlock
+ {
+ finishLexerRule((RuleAST)$RULE, $TOKEN_REF, $lexerRuleBlock.start);
+ currentRuleName=null; currentRuleAST=null;
+ }
+ )
+ ;
+
+rule
+@init {
+ enterRule($start);
+ List<GrammarAST> mods = new ArrayList<GrammarAST>();
+ List<GrammarAST> actions = new ArrayList<GrammarAST>(); // track roots
+ currentOuterAltNumber=0;
+}
+@after {
+ exitRule($start);
+}
+ : ^( RULE RULE_REF {currentRuleName=$RULE_REF.text; currentRuleAST=$RULE;}
+ (^(RULEMODIFIERS (m=ruleModifier{mods.add($m.start);})+))?
+ ARG_ACTION?
+ ret=ruleReturns?
+ thr=throwsSpec?
+ loc=locals?
+ ( opts=optionsSpec
+ | a=ruleAction {actions.add($a.start);}
+ )*
+ {discoverRule((RuleAST)$RULE, $RULE_REF, mods, (ActionAST)$ARG_ACTION,
+ $ret.start!=null?(ActionAST)$ret.start.getChild(0):null,
+ $thr.start, $opts.start,
+ $loc.start!=null?(ActionAST)$loc.start.getChild(0):null,
+ actions, (GrammarAST)input.LT(1));}
+ ruleBlock exceptionGroup
+ {finishRule((RuleAST)$RULE, $RULE_REF, $ruleBlock.start); currentRuleName=null; currentRuleAST=null;}
+ )
+ ;
+
+exceptionGroup
+@init {
+ enterExceptionGroup($start);
+}
+@after {
+ exitExceptionGroup($start);
+}
+ : exceptionHandler* finallyClause?
+ ;
+
+exceptionHandler
+@init {
+ enterExceptionHandler($start);
+}
+@after {
+ exitExceptionHandler($start);
+}
+ : ^(CATCH ARG_ACTION ACTION) {ruleCatch($ARG_ACTION, (ActionAST)$ACTION);}
+ ;
+
+finallyClause
+@init {
+ enterFinallyClause($start);
+}
+@after {
+ exitFinallyClause($start);
+}
+ : ^(FINALLY ACTION) {finallyAction((ActionAST)$ACTION);}
+ ;
+
+locals
+@init {
+ enterLocals($start);
+}
+@after {
+ exitLocals($start);
+}
+ : ^(LOCALS ARG_ACTION)
+ ;
+
+ruleReturns
+@init {
+ enterRuleReturns($start);
+}
+@after {
+ exitRuleReturns($start);
+}
+ : ^(RETURNS ARG_ACTION)
+ ;
+
+throwsSpec
+@init {
+ enterThrowsSpec($start);
+}
+@after {
+ exitThrowsSpec($start);
+}
+ : ^(THROWS ID+)
+ ;
+
+ruleAction
+@init {
+ enterRuleAction($start);
+}
+@after {
+ exitRuleAction($start);
+}
+ : ^(AT ID ACTION)
+ ;
+
+ruleModifier
+@init {
+ enterRuleModifier($start);
+}
+@after {
+ exitRuleModifier($start);
+}
+ : PUBLIC
+ | PRIVATE
+ | PROTECTED
+ | FRAGMENT
+ ;
+
+lexerRuleBlock
+@init {
+ enterLexerRuleBlock($start);
+}
+@after {
+ exitLexerRuleBlock($start);
+}
+ : ^( BLOCK
+ ( {
+ currentOuterAltRoot = (GrammarAST)input.LT(1);
+ currentOuterAltNumber++;
+ }
+ lexerOuterAlternative
+ )+
+ )
+ ;
+
+ruleBlock
+@init {
+ enterRuleBlock($start);
+}
+@after {
+ exitRuleBlock($start);
+}
+ : ^( BLOCK
+ ( {
+ currentOuterAltRoot = (GrammarAST)input.LT(1);
+ currentOuterAltNumber++;
+ }
+ outerAlternative
+ )+
+ )
+ ;
+
+lexerOuterAlternative
+@init {
+ enterLexerOuterAlternative((AltAST)$start);
+ discoverOuterAlt((AltAST)$start);
+}
+@after {
+ finishOuterAlt((AltAST)$start);
+ exitLexerOuterAlternative((AltAST)$start);
+}
+ : lexerAlternative
+ ;
+
+
+outerAlternative
+@init {
+ enterOuterAlternative((AltAST)$start);
+ discoverOuterAlt((AltAST)$start);
+}
+@after {
+ finishOuterAlt((AltAST)$start);
+ exitOuterAlternative((AltAST)$start);
+}
+ : alternative
+ ;
+
+lexerAlternative
+@init {
+ enterLexerAlternative($start);
+}
+@after {
+ exitLexerAlternative($start);
+}
+ : ^(LEXER_ALT_ACTION lexerElements lexerCommand+)
+ | lexerElements
+ ;
+
+lexerElements
+@init {
+ enterLexerElements($start);
+}
+@after {
+ exitLexerElements($start);
+}
+ : ^(ALT lexerElement+)
+ ;
+
+lexerElement
+@init {
+ enterLexerElement($start);
+}
+@after {
+ exitLexerElement($start);
+}
+ : labeledLexerElement
+ | lexerAtom
+ | lexerSubrule
+ | ACTION {actionInAlt((ActionAST)$ACTION);}
+ | SEMPRED {sempredInAlt((PredAST)$SEMPRED);}
+ | ^(ACTION elementOptions) {actionInAlt((ActionAST)$ACTION);}
+ | ^(SEMPRED elementOptions) {sempredInAlt((PredAST)$SEMPRED);}
+ | EPSILON
+ ;
+
+labeledLexerElement
+@init {
+ enterLabeledLexerElement($start);
+}
+@after {
+ exitLabeledLexerElement($start);
+}
+ : ^((ASSIGN|PLUS_ASSIGN) ID (lexerAtom|block))
+ ;
+
+lexerBlock
+@init {
+ enterLexerBlock($start);
+}
+@after {
+ exitLexerBlock($start);
+}
+ : ^(BLOCK optionsSpec? lexerAlternative+)
+ ;
+
+lexerAtom
+@init {
+ enterLexerAtom($start);
+}
+@after {
+ exitLexerAtom($start);
+}
+ : terminal
+ | ^(NOT blockSet)
+ | blockSet
+ | ^(WILDCARD elementOptions)
+ | WILDCARD
+ | LEXER_CHAR_SET
+ | range
+ | ruleref
+ ;
+
+actionElement
+@init {
+ enterActionElement($start);
+}
+@after {
+ exitActionElement($start);
+}
+ : ACTION
+ | ^(ACTION elementOptions)
+ | SEMPRED
+ | ^(SEMPRED elementOptions)
+ ;
+
+alternative
+@init {
+ enterAlternative((AltAST)$start);
+ discoverAlt((AltAST)$start);
+}
+@after {
+ finishAlt((AltAST)$start);
+ exitAlternative((AltAST)$start);
+}
+ : ^(ALT elementOptions? element+)
+ | ^(ALT elementOptions? EPSILON)
+ ;
+
+lexerCommand
+@init {
+ enterLexerCommand($start);
+}
+@after {
+ exitLexerCommand($start);
+}
+ : ^(LEXER_ACTION_CALL ID lexerCommandExpr)
+ {lexerCallCommand(currentOuterAltNumber, $ID, $lexerCommandExpr.start);}
+ | ID
+ {lexerCommand(currentOuterAltNumber, $ID);}
+ ;
+
+lexerCommandExpr
+@init {
+ enterLexerCommandExpr($start);
+}
+@after {
+ exitLexerCommandExpr($start);
+}
+ : ID
+ | INT
+ ;
+
+element
+@init {
+ enterElement($start);
+}
+@after {
+ exitElement($start);
+}
+ : labeledElement
+ | atom
+ | subrule
+ | ACTION {actionInAlt((ActionAST)$ACTION);}
+ | SEMPRED {sempredInAlt((PredAST)$SEMPRED);}
+ | ^(ACTION elementOptions) {actionInAlt((ActionAST)$ACTION);}
+ | ^(SEMPRED elementOptions) {sempredInAlt((PredAST)$SEMPRED);}
+
+ | ^(NOT blockSet)
+ | ^(NOT block)
+ ;
+
+astOperand
+@init {
+ enterAstOperand($start);
+}
+@after {
+ exitAstOperand($start);
+}
+ : atom
+ | ^(NOT blockSet)
+ | ^(NOT block)
+ ;
+
+labeledElement
+@init {
+ enterLabeledElement($start);
+}
+@after {
+ exitLabeledElement($start);
+}
+ : ^((ASSIGN|PLUS_ASSIGN) ID element) {label($start, $ID, $element.start);}
+ ;
+
+subrule
+@init {
+ enterSubrule($start);
+}
+@after {
+ exitSubrule($start);
+}
+ : ^(blockSuffix block)
+ | block
+ ;
+
+lexerSubrule
+@init {
+ enterLexerSubrule($start);
+}
+@after {
+ exitLexerSubrule($start);
+}
+ : ^(blockSuffix lexerBlock)
+ | lexerBlock
+ ;
+
+blockSuffix
+@init {
+ enterBlockSuffix($start);
+}
+@after {
+ exitBlockSuffix($start);
+}
+ : ebnfSuffix
+ ;
+
+ebnfSuffix
+@init {
+ enterEbnfSuffix($start);
+}
+@after {
+ exitEbnfSuffix($start);
+}
+ : OPTIONAL
+ | CLOSURE
+ | POSITIVE_CLOSURE
+ ;
+
+atom
+@init {
+ enterAtom($start);
+}
+@after {
+ exitAtom($start);
+}
+ : ^(DOT ID terminal)
+ | ^(DOT ID ruleref)
+ | ^(WILDCARD elementOptions) {wildcardRef($WILDCARD);}
+ | WILDCARD {wildcardRef($WILDCARD);}
+ | terminal
+ | blockSet
+ | ruleref
+ ;
+
+blockSet
+@init {
+ enterBlockSet($start);
+}
+@after {
+ exitBlockSet($start);
+}
+ : ^(SET setElement+)
+ ;
+
+setElement
+@init {
+ enterSetElement($start);
+}
+@after {
+ exitSetElement($start);
+}
+ : ^(STRING_LITERAL elementOptions) {stringRef((TerminalAST)$STRING_LITERAL);}
+ | ^(TOKEN_REF elementOptions) {tokenRef((TerminalAST)$TOKEN_REF);}
+ | STRING_LITERAL {stringRef((TerminalAST)$STRING_LITERAL);}
+ | TOKEN_REF {tokenRef((TerminalAST)$TOKEN_REF);}
+ | ^(RANGE a=STRING_LITERAL b=STRING_LITERAL)
+ {
+ stringRef((TerminalAST)$a);
+ stringRef((TerminalAST)$b);
+ }
+ | LEXER_CHAR_SET
+ ;
+
+block
+@init {
+ enterBlock($start);
+}
+@after {
+ exitBlock($start);
+}
+ : ^(BLOCK optionsSpec? ruleAction* ACTION? alternative+)
+ ;
+
+ruleref
+@init {
+ enterRuleref($start);
+}
+@after {
+ exitRuleref($start);
+}
+ : ^(RULE_REF arg=ARG_ACTION? elementOptions?)
+ {
+ ruleRef($RULE_REF, (ActionAST)$ARG_ACTION);
+ if ( $arg!=null ) actionInAlt((ActionAST)$arg);
+ }
+ ;
+
+range
+@init {
+ enterRange($start);
+}
+@after {
+ exitRange($start);
+}
+ : ^(RANGE STRING_LITERAL STRING_LITERAL)
+ ;
+
+terminal
+@init {
+ enterTerminal($start);
+}
+@after {
+ exitTerminal($start);
+}
+ : ^(STRING_LITERAL elementOptions)
+ {stringRef((TerminalAST)$STRING_LITERAL);}
+ | STRING_LITERAL {stringRef((TerminalAST)$STRING_LITERAL);}
+ | ^(TOKEN_REF elementOptions) {tokenRef((TerminalAST)$TOKEN_REF);}
+ | TOKEN_REF {tokenRef((TerminalAST)$TOKEN_REF);}
+ ;
+
+elementOptions
+@init {
+ enterElementOptions($start);
+}
+@after {
+ exitElementOptions($start);
+}
+ : ^(ELEMENT_OPTIONS elementOption[(GrammarASTWithOptions)$start.getParent()]*)
+ ;
+
+elementOption[GrammarASTWithOptions t]
+@init {
+ enterElementOption($start);
+}
+@after {
+ exitElementOption($start);
+}
+ : ID {elementOption(t, $ID, null);}
+ | ^(ASSIGN id=ID v=ID) {elementOption(t, $id, $v);}
+ | ^(ASSIGN ID v=STRING_LITERAL) {elementOption(t, $ID, $v);}
+ | ^(ASSIGN ID v=ACTION) {elementOption(t, $ID, $v);}
+ | ^(ASSIGN ID v=INT) {elementOption(t, $ID, $v);}
+ ;
diff --git a/tool/src/org/antlr/v4/parse/LeftRecursiveRuleWalker.g b/tool/src/org/antlr/v4/parse/LeftRecursiveRuleWalker.g
new file mode 100644
index 0000000..774243f
--- /dev/null
+++ b/tool/src/org/antlr/v4/parse/LeftRecursiveRuleWalker.g
@@ -0,0 +1,224 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** Find left-recursive rules */
+tree grammar LeftRecursiveRuleWalker;
+
+options {
+ tokenVocab=ANTLRParser;
+ ASTLabelType=GrammarAST;
+}
+
+@header {
+package org.antlr.v4.parse;
+
+import org.antlr.v4.misc.*;
+import org.antlr.v4.tool.*;
+import org.antlr.v4.tool.ast.*;
+}
+
+@members {
+private String ruleName;
+private int currentOuterAltNumber; // which outer alt of rule?
+public int numAlts; // how many alts for this rule total?
+
+public void setAltAssoc(AltAST altTree, int alt) {}
+public void binaryAlt(AltAST altTree, int alt) {}
+public void prefixAlt(AltAST altTree, int alt) {}
+public void suffixAlt(AltAST altTree, int alt) {}
+public void otherAlt(AltAST altTree, int alt) {}
+public void setReturnValues(GrammarAST t) {}
+}
+
+@rulecatch { }
+
+// TODO: can get parser errors for not matching pattern; make them go away
+public
+rec_rule returns [boolean isLeftRec]
+@init
+{
+ currentOuterAltNumber = 1;
+}
+ : ^( r=RULE id=RULE_REF {ruleName=$id.getText();}
+ ruleModifier?
+// (ARG_ACTION)? shouldn't allow args, right?
+ (^(RETURNS a=ARG_ACTION {setReturnValues($a);}))?
+// ( ^(THROWS .+) )? don't allow
+ ( ^(LOCALS ARG_ACTION) )? // TODO: copy these to gen'd code
+ ( ^(OPTIONS .*)
+ | ^(AT ID ACTION) // TODO: copy
+ )*
+ ruleBlock {$isLeftRec = $ruleBlock.isLeftRec;}
+ exceptionGroup
+ )
+ ;
+
+exceptionGroup
+ : exceptionHandler* finallyClause?
+ ;
+
+exceptionHandler
+ : ^(CATCH ARG_ACTION ACTION)
+ ;
+
+finallyClause
+ : ^(FINALLY ACTION)
+ ;
+
+ruleModifier
+ : PUBLIC
+ | PRIVATE
+ | PROTECTED
+ ;
+
+ruleBlock returns [boolean isLeftRec]
+@init{boolean lr=false; this.numAlts = $start.getChildCount();}
+ : ^( BLOCK
+ (
+ o=outerAlternative
+ {if ($o.isLeftRec) $isLeftRec = true;}
+ {currentOuterAltNumber++;}
+ )+
+ )
+ ;
+
+/** An alt is either prefix, suffix, binary, or ternary operation or "other" */
+outerAlternative returns [boolean isLeftRec]
+ : (binary)=> binary
+ {binaryAlt((AltAST)$start, currentOuterAltNumber); $isLeftRec=true;}
+ | (prefix)=> prefix
+ {prefixAlt((AltAST)$start, currentOuterAltNumber);}
+ | (suffix)=> suffix
+ {suffixAlt((AltAST)$start, currentOuterAltNumber); $isLeftRec=true;}
+ | nonLeftRecur {otherAlt((AltAST)$start, currentOuterAltNumber);}
+ ;
+
+binary
+ : ^( ALT elementOptions? recurse element* recurse epsilonElement* )
+ {setAltAssoc((AltAST)$ALT,currentOuterAltNumber);}
+ ;
+
+prefix
+ : ^( ALT elementOptions?
+ ({!((CommonTree)input.LT(1)).getText().equals(ruleName)}? element)+
+ recurse epsilonElement*
+ )
+ {setAltAssoc((AltAST)$ALT,currentOuterAltNumber);}
+ ;
+
+suffix
+ : ^( ALT elementOptions? recurse element+ )
+ {setAltAssoc((AltAST)$ALT,currentOuterAltNumber);}
+ ;
+
+nonLeftRecur
+ : ^(ALT elementOptions? element+)
+ ;
+
+recurse
+ : ^(ASSIGN ID recurseNoLabel)
+ | ^(PLUS_ASSIGN ID recurseNoLabel)
+ | recurseNoLabel
+ ;
+
+recurseNoLabel : {((CommonTree)input.LT(1)).getText().equals(ruleName)}? RULE_REF;
+
+token returns [GrammarAST t=null]
+ : ^(ASSIGN ID s=token {$t = $s.t;})
+ | ^(PLUS_ASSIGN ID s=token {$t = $s.t;})
+ | b=STRING_LITERAL {$t = $b;}
+ | ^(b=STRING_LITERAL elementOptions) {$t = $b;}
+ | ^(c=TOKEN_REF elementOptions) {$t = $c;}
+ | c=TOKEN_REF {$t = $c;}
+ ;
+
+elementOptions
+ : ^(ELEMENT_OPTIONS elementOption*)
+ ;
+
+elementOption
+ : ID
+ | ^(ASSIGN ID ID)
+ | ^(ASSIGN ID STRING_LITERAL)
+ | ^(ASSIGN ID ACTION)
+ | ^(ASSIGN ID INT)
+ ;
+
+element
+ : atom
+ | ^(NOT element)
+ | ^(RANGE atom atom)
+ | ^(ASSIGN ID element)
+ | ^(PLUS_ASSIGN ID element)
+ | ^(SET setElement+)
+ | RULE_REF
+ | ebnf
+ | epsilonElement
+ ;
+
+epsilonElement
+ : ACTION
+ | SEMPRED
+ | EPSILON
+ | ^(ACTION elementOptions)
+ | ^(SEMPRED elementOptions)
+ ;
+
+setElement
+ : ^(STRING_LITERAL elementOptions)
+ | ^(TOKEN_REF elementOptions)
+ | STRING_LITERAL
+ | TOKEN_REF
+ ;
+
+ebnf: block
+ | ^( OPTIONAL block )
+ | ^( CLOSURE block )
+ | ^( POSITIVE_CLOSURE block )
+ ;
+
+block
+ : ^(BLOCK ACTION? alternative+)
+ ;
+
+alternative
+ : ^(ALT elementOptions? element+)
+ ;
+
+atom
+ : ^(RULE_REF ARG_ACTION? elementOptions?)
+ | ^(STRING_LITERAL elementOptions)
+ | STRING_LITERAL
+ | ^(TOKEN_REF elementOptions)
+ | TOKEN_REF
+ | ^(WILDCARD elementOptions)
+ | WILDCARD
+ | ^(DOT ID element)
+ ;
diff --git a/tool/src/org/antlr/v4/parse/ResyncToEndOfRuleBlock.java b/tool/src/org/antlr/v4/parse/ResyncToEndOfRuleBlock.java
new file mode 100644
index 0000000..aefff83
--- /dev/null
+++ b/tool/src/org/antlr/v4/parse/ResyncToEndOfRuleBlock.java
@@ -0,0 +1,37 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.parse;
+
+/** Used to throw us out of deeply nested element back to end of a rule's
+ * alt list. Note it's not under RecognitionException.
+ */
+public class ResyncToEndOfRuleBlock extends RuntimeException {
+}
diff --git a/tool/src/org/antlr/v4/parse/ScopeParser.java b/tool/src/org/antlr/v4/parse/ScopeParser.java
new file mode 100644
index 0000000..a0ce182
--- /dev/null
+++ b/tool/src/org/antlr/v4/parse/ScopeParser.java
@@ -0,0 +1,297 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.parse;
+
+import org.antlr.runtime.BaseRecognizer;
+import org.antlr.runtime.CommonToken;
+import org.antlr.v4.runtime.misc.Pair;
+import org.antlr.v4.tool.Attribute;
+import org.antlr.v4.tool.AttributeDict;
+import org.antlr.v4.tool.ErrorType;
+import org.antlr.v4.tool.Grammar;
+import org.antlr.v4.tool.ast.ActionAST;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** Parse args, return values, locals
+ *
+ * rule[arg1, arg2, ..., argN] returns [ret1, ..., retN]
+ *
+ * text is target language dependent. Java/C#/C/C++ would
+ * use "int i" but ruby/python would use "i".
+ */
+public class ScopeParser {
+ /** Given an arg or retval scope definition list like
+ *
+ * Map<String, String>, int[] j3, char *foo32[3]
+ *
+ * or
+ *
+ * int i=3, j=a[34]+20
+ *
+ * convert to an attribute scope.
+ */
+ public static AttributeDict parseTypedArgList(ActionAST action, String s, Grammar g) {
+ return parse(action, s, ',', g);
+ }
+
+ public static AttributeDict parse(ActionAST action, String s, char separator, Grammar g) {
+ AttributeDict dict = new AttributeDict();
+ List<Pair<String, Integer>> decls = splitDecls(s, separator);
+ for (Pair<String, Integer> decl : decls) {
+// System.out.println("decl="+decl);
+ if ( decl.a.trim().length()>0 ) {
+ Attribute a = parseAttributeDef(action, decl, g);
+ dict.add(a);
+ }
+ }
+ return dict;
+ }
+
+ /** For decls like "String foo" or "char *foo32[]" compute the ID
+ * and type declarations. Also handle "int x=3" and 'T t = new T("foo")'
+ * but if the separator is ',' you cannot use ',' in the initvalue
+ * unless you escape use "\," escape.
+ */
+ public static Attribute parseAttributeDef(ActionAST action, Pair<String, Integer> decl, Grammar g) {
+ if ( decl.a==null ) return null;
+ Attribute attr = new Attribute();
+ boolean inID = false;
+ int start = -1;
+ int rightEdgeOfDeclarator = decl.a.length()-1;
+ int equalsIndex = decl.a.indexOf('=');
+ if ( equalsIndex>0 ) {
+ // everything after the '=' is the init value
+ attr.initValue = decl.a.substring(equalsIndex+1,decl.a.length());
+ rightEdgeOfDeclarator = equalsIndex-1;
+ }
+ // walk backwards looking for start of an ID
+ for (int i=rightEdgeOfDeclarator; i>=0; i--) {
+ // if we haven't found the end yet, keep going
+ if ( !inID && Character.isLetterOrDigit(decl.a.charAt(i)) ) {
+ inID = true;
+ }
+ else if ( inID &&
+ !(Character.isLetterOrDigit(decl.a.charAt(i))||
+ decl.a.charAt(i)=='_') ) {
+ start = i+1;
+ break;
+ }
+ }
+ if ( start<0 && inID ) {
+ start = 0;
+ }
+ if ( start<0 ) {
+ g.tool.errMgr.grammarError(ErrorType.CANNOT_FIND_ATTRIBUTE_NAME_IN_DECL, g.fileName, action.token, decl);
+ }
+ // walk forwards looking for end of an ID
+ int stop=-1;
+ for (int i=start; i<=rightEdgeOfDeclarator; i++) {
+ // if we haven't found the end yet, keep going
+ if ( !(Character.isLetterOrDigit(decl.a.charAt(i))||
+ decl.a.charAt(i)=='_') )
+ {
+ stop = i;
+ break;
+ }
+ if ( i==rightEdgeOfDeclarator ) {
+ stop = i+1;
+ }
+ }
+
+ // the name is the last ID
+ attr.name = decl.a.substring(start,stop);
+
+ // the type is the decl minus the ID (could be empty)
+ attr.type = decl.a.substring(0,start);
+ if ( stop<=rightEdgeOfDeclarator ) {
+ attr.type += decl.a.substring(stop,rightEdgeOfDeclarator+1);
+ }
+ attr.type = attr.type.trim();
+ if ( attr.type.length()==0 ) {
+ attr.type = null;
+ }
+
+ attr.decl = decl.a;
+
+ if (action != null) {
+ String actionText = action.getText();
+ int[] lines = new int[actionText.length()];
+ int[] charPositionInLines = new int[actionText.length()];
+ for (int i = 0, line = 0, col = 0; i < actionText.length(); i++, col++) {
+ lines[i] = line;
+ charPositionInLines[i] = col;
+ if (actionText.charAt(i) == '\n') {
+ line++;
+ col = -1;
+ }
+ }
+
+ int[] charIndexes = new int[actionText.length()];
+ for (int i = 0, j = 0; i < actionText.length(); i++, j++) {
+ charIndexes[j] = i;
+ if (i < actionText.length() - 1 && actionText.charAt(i) == '/' && actionText.charAt(i + 1) == '/') {
+ while (i < actionText.length() && actionText.charAt(i) != '\n') {
+ i++;
+ }
+ }
+ }
+
+ int declOffset = charIndexes[decl.b];
+ int declLine = lines[declOffset + start];
+
+ int line = action.getToken().getLine() + declLine;
+ int charPositionInLine = charPositionInLines[declOffset + start];
+ if (declLine == 0) {
+ /* offset for the start position of the ARG_ACTION token, plus 1
+ * since the ARG_ACTION text had the leading '[' stripped before
+ * reaching the scope parser.
+ */
+ charPositionInLine += action.getToken().getCharPositionInLine() + 1;
+ }
+
+ int offset = ((CommonToken)action.getToken()).getStartIndex();
+ attr.token = new CommonToken(action.getToken().getInputStream(), ANTLRParser.ID, BaseRecognizer.DEFAULT_TOKEN_CHANNEL, offset + declOffset + start + 1, offset + declOffset + stop);
+ attr.token.setLine(line);
+ attr.token.setCharPositionInLine(charPositionInLine);
+ assert attr.name.equals(attr.token.getText()) : "Attribute text should match the pseudo-token text at this point.";
+ }
+
+ return attr;
+ }
+
+ /** Given an argument list like
+ *
+ * x, (*a).foo(21,33), 3.2+1, '\n',
+ * "a,oo\nick", {bl, "fdkj"eck}, ["cat\n,", x, 43]
+ *
+ * convert to a list of attributes. Allow nested square brackets etc...
+ * Set separatorChar to ';' or ',' or whatever you want.
+ */
+ public static List<Pair<String, Integer>> splitDecls(String s, int separatorChar) {
+ List<Pair<String, Integer>> args = new ArrayList<Pair<String, Integer>>();
+ _splitArgumentList(s, 0, -1, separatorChar, args);
+ return args;
+ }
+
+ public static int _splitArgumentList(String actionText,
+ int start,
+ int targetChar,
+ int separatorChar,
+ List<Pair<String, Integer>> args)
+ {
+ if ( actionText==null ) {
+ return -1;
+ }
+
+ actionText = actionText.replaceAll("//[^\\n]*", "");
+ int n = actionText.length();
+ //System.out.println("actionText@"+start+"->"+(char)targetChar+"="+actionText.substring(start,n));
+ int p = start;
+ int last = p;
+ while ( p<n && actionText.charAt(p)!=targetChar ) {
+ int c = actionText.charAt(p);
+ switch ( c ) {
+ case '\'' :
+ p++;
+ while ( p<n && actionText.charAt(p)!='\'' ) {
+ if ( actionText.charAt(p)=='\\' && (p+1)<n &&
+ actionText.charAt(p+1)=='\'' )
+ {
+ p++; // skip escaped quote
+ }
+ p++;
+ }
+ p++;
+ break;
+ case '"' :
+ p++;
+ while ( p<n && actionText.charAt(p)!='\"' ) {
+ if ( actionText.charAt(p)=='\\' && (p+1)<n &&
+ actionText.charAt(p+1)=='\"' )
+ {
+ p++; // skip escaped quote
+ }
+ p++;
+ }
+ p++;
+ break;
+ case '(' :
+ p = _splitArgumentList(actionText,p+1,')',separatorChar,args);
+ break;
+ case '{' :
+ p = _splitArgumentList(actionText,p+1,'}',separatorChar,args);
+ break;
+ case '<' :
+ if ( actionText.indexOf('>',p+1)>=p ) {
+ // do we see a matching '>' ahead? if so, hope it's a generic
+ // and not less followed by expr with greater than
+ p = _splitArgumentList(actionText,p+1,'>',separatorChar,args);
+ }
+ else {
+ p++; // treat as normal char
+ }
+ break;
+ case '[' :
+ p = _splitArgumentList(actionText,p+1,']',separatorChar,args);
+ break;
+ default :
+ if ( c==separatorChar && targetChar==-1 ) {
+ String arg = actionText.substring(last, p);
+ int index = last;
+ while (index < p && Character.isWhitespace(actionText.charAt(index))) {
+ index++;
+ }
+ //System.out.println("arg="+arg);
+ args.add(new Pair<String, Integer>(arg.trim(), index));
+ last = p+1;
+ }
+ p++;
+ break;
+ }
+ }
+ if ( targetChar==-1 && p<=n ) {
+ String arg = actionText.substring(last, p).trim();
+ int index = last;
+ while (index < p && Character.isWhitespace(actionText.charAt(index))) {
+ index++;
+ }
+ //System.out.println("arg="+arg);
+ if ( arg.length()>0 ) {
+ args.add(new Pair<String, Integer>(arg.trim(), index));
+ }
+ }
+ p++;
+ return p;
+ }
+
+}
diff --git a/tool/src/org/antlr/v4/parse/TokenVocabParser.java b/tool/src/org/antlr/v4/parse/TokenVocabParser.java
new file mode 100644
index 0000000..85398e6
--- /dev/null
+++ b/tool/src/org/antlr/v4/parse/TokenVocabParser.java
@@ -0,0 +1,175 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.parse;
+
+import org.antlr.runtime.Token;
+import org.antlr.v4.Tool;
+import org.antlr.v4.codegen.CodeGenerator;
+import org.antlr.v4.tool.ErrorType;
+import org.antlr.v4.tool.Grammar;
+import org.antlr.v4.tool.ast.GrammarAST;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/** */
+public class TokenVocabParser {
+ protected final Grammar g;
+
+ public TokenVocabParser(Grammar g) {
+ this.g = g;
+ }
+
+ /** Load a vocab file {@code <vocabName>.tokens} and return mapping. */
+ public Map<String,Integer> load() {
+ Map<String,Integer> tokens = new LinkedHashMap<String,Integer>();
+ int maxTokenType = -1;
+ File fullFile = getImportedVocabFile();
+ FileInputStream fis = null;
+ BufferedReader br = null;
+ Tool tool = g.tool;
+ String vocabName = g.getOptionString("tokenVocab");
+ try {
+ Pattern tokenDefPattern = Pattern.compile("([^\n]+?)[ \\t]*?=[ \\t]*?([0-9]+)");
+ fis = new FileInputStream(fullFile);
+ InputStreamReader isr;
+ if (tool.grammarEncoding != null) {
+ isr = new InputStreamReader(fis, tool.grammarEncoding);
+ }
+ else {
+ isr = new InputStreamReader(fis);
+ }
+
+ br = new BufferedReader(isr);
+ String tokenDef = br.readLine();
+ int lineNum = 1;
+ while ( tokenDef!=null ) {
+ Matcher matcher = tokenDefPattern.matcher(tokenDef);
+ if ( matcher.find() ) {
+ String tokenID = matcher.group(1);
+ String tokenTypeS = matcher.group(2);
+ int tokenType;
+ try {
+ tokenType = Integer.valueOf(tokenTypeS);
+ }
+ catch (NumberFormatException nfe) {
+ tool.errMgr.toolError(ErrorType.TOKENS_FILE_SYNTAX_ERROR,
+ vocabName + CodeGenerator.VOCAB_FILE_EXTENSION,
+ " bad token type: "+tokenTypeS,
+ lineNum);
+ tokenType = Token.INVALID_TOKEN_TYPE;
+ }
+ tool.log("grammar", "import "+tokenID+"="+tokenType);
+ tokens.put(tokenID, tokenType);
+ maxTokenType = Math.max(maxTokenType,tokenType);
+ lineNum++;
+ }
+ else {
+ if ( tokenDef.length()>0 ) { // ignore blank lines
+ tool.errMgr.toolError(ErrorType.TOKENS_FILE_SYNTAX_ERROR,
+ vocabName + CodeGenerator.VOCAB_FILE_EXTENSION,
+ " bad token def: " + tokenDef,
+ lineNum);
+ }
+ }
+ tokenDef = br.readLine();
+ }
+ }
+ catch (FileNotFoundException fnfe) {
+ GrammarAST inTree = g.ast.getOptionAST("tokenVocab");
+ String inTreeValue = inTree.getToken().getText();
+ if ( vocabName.equals(inTreeValue) ) {
+ tool.errMgr.grammarError(ErrorType.CANNOT_FIND_TOKENS_FILE_REFD_IN_GRAMMAR,
+ g.fileName,
+ inTree.getToken(),
+ fullFile);
+ }
+ else { // must be from -D option on cmd-line not token in tree
+ tool.errMgr.toolError(ErrorType.CANNOT_FIND_TOKENS_FILE_GIVEN_ON_CMDLINE,
+ fullFile,
+ g.name);
+ }
+ }
+ catch (Exception e) {
+ tool.errMgr.toolError(ErrorType.ERROR_READING_TOKENS_FILE,
+ e,
+ fullFile,
+ e.getMessage());
+ }
+ finally {
+ try {
+ if ( br!=null ) br.close();
+ }
+ catch (IOException ioe) {
+ tool.errMgr.toolError(ErrorType.ERROR_READING_TOKENS_FILE,
+ ioe,
+ fullFile,
+ ioe.getMessage());
+ }
+ }
+ return tokens;
+ }
+
+ /** Return a File descriptor for vocab file. Look in library or
+ * in -o output path. antlr -o foo T.g4 U.g4 where U needs T.tokens
+ * won't work unless we look in foo too. If we do not find the
+ * file in the lib directory then must assume that the .tokens file
+ * is going to be generated as part of this build and we have defined
+ * .tokens files so that they ALWAYS are generated in the base output
+ * directory, which means the current directory for the command line tool if there
+ * was no output directory specified.
+ */
+ public File getImportedVocabFile() {
+ String vocabName = g.getOptionString("tokenVocab");
+ File f = new File(g.tool.libDirectory,
+ File.separator +
+ vocabName +
+ CodeGenerator.VOCAB_FILE_EXTENSION);
+ if (f.exists()) {
+ return f;
+ }
+
+ // We did not find the vocab file in the lib directory, so we need
+ // to look for it in the output directory which is where .tokens
+ // files are generated (in the base, not relative to the input
+ // location.)
+ f = new File(g.tool.outputDirectory, vocabName + CodeGenerator.VOCAB_FILE_EXTENSION);
+ return f;
+ }
+}
diff --git a/tool/src/org/antlr/v4/parse/ToolANTLRLexer.java b/tool/src/org/antlr/v4/parse/ToolANTLRLexer.java
new file mode 100644
index 0000000..625fdd7
--- /dev/null
+++ b/tool/src/org/antlr/v4/parse/ToolANTLRLexer.java
@@ -0,0 +1,57 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.parse;
+
+import org.antlr.runtime.CharStream;
+import org.antlr.runtime.RecognitionException;
+import org.antlr.runtime.Token;
+import org.antlr.v4.Tool;
+import org.antlr.v4.tool.ErrorType;
+
+public class ToolANTLRLexer extends ANTLRLexer {
+ public Tool tool;
+
+ public ToolANTLRLexer(CharStream input, Tool tool) {
+ super(input);
+ this.tool = tool;
+ }
+
+ @Override
+ public void displayRecognitionError(String[] tokenNames, RecognitionException e) {
+ String msg = getErrorMessage(e, tokenNames);
+ tool.errMgr.syntaxError(ErrorType.SYNTAX_ERROR, getSourceName(), e.token, e, msg);
+ }
+
+ @Override
+ public void grammarError(ErrorType etype, Token token, Object... args) {
+ tool.errMgr.grammarError(etype, getSourceName(), token, args);
+ }
+}
diff --git a/tool/src/org/antlr/v4/parse/ToolANTLRParser.java b/tool/src/org/antlr/v4/parse/ToolANTLRParser.java
new file mode 100644
index 0000000..168b0f8
--- /dev/null
+++ b/tool/src/org/antlr/v4/parse/ToolANTLRParser.java
@@ -0,0 +1,84 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.parse;
+
+import org.antlr.runtime.NoViableAltException;
+import org.antlr.runtime.Parser;
+import org.antlr.runtime.RecognitionException;
+import org.antlr.runtime.TokenStream;
+import org.antlr.v4.Tool;
+import org.antlr.v4.tool.ErrorType;
+
+/** Override error handling for use with ANTLR tool itself; leaves
+ * nothing in grammar associated with Tool so others can use in IDEs, ...
+ */
+public class ToolANTLRParser extends ANTLRParser {
+ public Tool tool;
+
+ public ToolANTLRParser(TokenStream input, Tool tool) {
+ super(input);
+ this.tool = tool;
+ }
+
+ @Override
+ public void displayRecognitionError(String[] tokenNames,
+ RecognitionException e)
+ {
+ String msg = getParserErrorMessage(this, e);
+ if ( !paraphrases.isEmpty() ) {
+ String paraphrase = paraphrases.peek();
+ msg = msg+" while "+paraphrase;
+ }
+ // List stack = getRuleInvocationStack(e, this.getClass().getName());
+ // msg += ", rule stack = "+stack;
+ tool.errMgr.syntaxError(ErrorType.SYNTAX_ERROR, getSourceName(), e.token, e, msg);
+ }
+
+ public String getParserErrorMessage(Parser parser, RecognitionException e) {
+ String msg;
+ if ( e instanceof NoViableAltException) {
+ String name = parser.getTokenErrorDisplay(e.token);
+ msg = name+" came as a complete surprise to me";
+ }
+ else if ( e instanceof v4ParserException) {
+ msg = ((v4ParserException)e).msg;
+ }
+ else {
+ msg = parser.getErrorMessage(e, parser.getTokenNames());
+ }
+ return msg;
+ }
+
+ @Override
+ public void grammarError(ErrorType etype, org.antlr.runtime.Token token, Object... args) {
+ tool.errMgr.grammarError(etype, getSourceName(), token, args);
+ }
+}
diff --git a/tool/src/org/antlr/v4/parse/v3TreeGrammarException.java b/tool/src/org/antlr/v4/parse/v3TreeGrammarException.java
new file mode 100644
index 0000000..c1fabfe
--- /dev/null
+++ b/tool/src/org/antlr/v4/parse/v3TreeGrammarException.java
@@ -0,0 +1,42 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.parse;
+
+import org.antlr.runtime.Token;
+import org.antlr.v4.runtime.misc.ParseCancellationException;
+
+public class v3TreeGrammarException extends ParseCancellationException {
+ public Token location;
+
+ public v3TreeGrammarException(Token location) {
+ this.location = location;
+ }
+}
diff --git a/tool/src/org/antlr/v4/parse/v4ParserException.java b/tool/src/org/antlr/v4/parse/v4ParserException.java
new file mode 100644
index 0000000..80cbb75
--- /dev/null
+++ b/tool/src/org/antlr/v4/parse/v4ParserException.java
@@ -0,0 +1,47 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.parse;
+
+import org.antlr.runtime.IntStream;
+import org.antlr.runtime.RecognitionException;
+
+/** */
+public class v4ParserException extends RecognitionException {
+ public String msg;
+ /** Used for remote debugger deserialization */
+ public v4ParserException() {}
+
+ public v4ParserException(String msg, IntStream input) {
+ super(input);
+ this.msg = msg;
+ }
+
+}
diff --git a/tool/src/org/antlr/v4/semantics/ActionSniffer.java b/tool/src/org/antlr/v4/semantics/ActionSniffer.java
new file mode 100644
index 0000000..2d48e25
--- /dev/null
+++ b/tool/src/org/antlr/v4/semantics/ActionSniffer.java
@@ -0,0 +1,113 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.semantics;
+
+import org.antlr.runtime.ANTLRStringStream;
+import org.antlr.runtime.Token;
+import org.antlr.v4.parse.ActionSplitter;
+import org.antlr.v4.tool.Alternative;
+import org.antlr.v4.tool.ErrorManager;
+import org.antlr.v4.tool.Grammar;
+import org.antlr.v4.tool.Rule;
+import org.antlr.v4.tool.ast.ActionAST;
+import org.antlr.v4.tool.ast.GrammarAST;
+import org.antlr.v4.tool.ast.TerminalAST;
+
+import java.util.List;
+
+/** Find token and rule refs plus refs to them in actions;
+ * side-effect: update Alternatives
+ */
+public class ActionSniffer extends BlankActionSplitterListener {
+ public Grammar g;
+ public Rule r; // null if action outside of rule
+ public Alternative alt; // null if action outside of alt; could be in rule
+ public ActionAST node;
+ public Token actionToken; // token within action
+ public ErrorManager errMgr;
+
+ public ActionSniffer(Grammar g, Rule r, Alternative alt, ActionAST node, Token actionToken) {
+ this.g = g;
+ this.r = r;
+ this.alt = alt;
+ this.node = node;
+ this.actionToken = actionToken;
+ this.errMgr = g.tool.errMgr;
+ }
+
+ public void examineAction() {
+ //System.out.println("examine "+actionToken);
+ ANTLRStringStream in = new ANTLRStringStream(actionToken.getText());
+ in.setLine(actionToken.getLine());
+ in.setCharPositionInLine(actionToken.getCharPositionInLine());
+ ActionSplitter splitter = new ActionSplitter(in, this);
+ // forces eval, triggers listener methods
+ node.chunks = splitter.getActionTokens();
+ }
+
+ public void processNested(Token actionToken) {
+ ANTLRStringStream in = new ANTLRStringStream(actionToken.getText());
+ in.setLine(actionToken.getLine());
+ in.setCharPositionInLine(actionToken.getCharPositionInLine());
+ ActionSplitter splitter = new ActionSplitter(in, this);
+ // forces eval, triggers listener methods
+ splitter.getActionTokens();
+ }
+
+
+ @Override
+ public void attr(String expr, Token x) { trackRef(x); }
+
+ @Override
+ public void qualifiedAttr(String expr, Token x, Token y) { trackRef(x); }
+
+ @Override
+ public void setAttr(String expr, Token x, Token rhs) {
+ trackRef(x);
+ processNested(rhs);
+ }
+
+ @Override
+ public void setNonLocalAttr(String expr, Token x, Token y, Token rhs) {
+ processNested(rhs);
+ }
+
+ public void trackRef(Token x) {
+ List<TerminalAST> xRefs = alt.tokenRefs.get(x.getText());
+ if ( xRefs!=null ) {
+ alt.tokenRefsInActions.map(x.getText(), node);
+ }
+ List<GrammarAST> rRefs = alt.ruleRefs.get(x.getText());
+ if ( rRefs!=null ) {
+ alt.ruleRefsInActions.map(x.getText(), node);
+ }
+ }
+}
diff --git a/tool/src/org/antlr/v4/semantics/AttributeChecks.java b/tool/src/org/antlr/v4/semantics/AttributeChecks.java
new file mode 100644
index 0000000..f702185
--- /dev/null
+++ b/tool/src/org/antlr/v4/semantics/AttributeChecks.java
@@ -0,0 +1,259 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.semantics;
+
+import org.antlr.runtime.ANTLRStringStream;
+import org.antlr.runtime.Token;
+import org.antlr.v4.parse.ActionSplitter;
+import org.antlr.v4.parse.ActionSplitterListener;
+import org.antlr.v4.tool.Alternative;
+import org.antlr.v4.tool.ErrorManager;
+import org.antlr.v4.tool.ErrorType;
+import org.antlr.v4.tool.Grammar;
+import org.antlr.v4.tool.LabelElementPair;
+import org.antlr.v4.tool.LabelType;
+import org.antlr.v4.tool.Rule;
+import org.antlr.v4.tool.ast.ActionAST;
+import org.antlr.v4.tool.ast.GrammarAST;
+
+import java.util.List;
+
+/** Trigger checks for various kinds of attribute expressions.
+ * no side-effects.
+ */
+public class AttributeChecks implements ActionSplitterListener {
+ public Grammar g;
+ public Rule r; // null if action outside of rule
+ public Alternative alt; // null if action outside of alt; could be in rule
+ public ActionAST node;
+ public Token actionToken; // token within action
+ public ErrorManager errMgr;
+
+ public AttributeChecks(Grammar g, Rule r, Alternative alt, ActionAST node, Token actionToken) {
+ this.g = g;
+ this.r = r;
+ this.alt = alt;
+ this.node = node;
+ this.actionToken = actionToken;
+ this.errMgr = g.tool.errMgr;
+ }
+
+ public static void checkAllAttributeExpressions(Grammar g) {
+ for (ActionAST act : g.namedActions.values()) {
+ AttributeChecks checker = new AttributeChecks(g, null, null, act, act.token);
+ checker.examineAction();
+ }
+
+ for (Rule r : g.rules.values()) {
+ for (ActionAST a : r.namedActions.values()) {
+ AttributeChecks checker = new AttributeChecks(g, r, null, a, a.token);
+ checker.examineAction();
+ }
+ for (int i=1; i<=r.numberOfAlts; i++) {
+ Alternative alt = r.alt[i];
+ for (ActionAST a : alt.actions) {
+ AttributeChecks checker =
+ new AttributeChecks(g, r, alt, a, a.token);
+ checker.examineAction();
+ }
+ }
+ for (GrammarAST e : r.exceptions) {
+ ActionAST a = (ActionAST)e.getChild(1);
+ AttributeChecks checker = new AttributeChecks(g, r, null, a, a.token);
+ checker.examineAction();
+ }
+ if ( r.finallyAction!=null ) {
+ AttributeChecks checker =
+ new AttributeChecks(g, r, null, r.finallyAction, r.finallyAction.token);
+ checker.examineAction();
+ }
+ }
+ }
+
+ public void examineAction() {
+ //System.out.println("examine "+actionToken);
+ ANTLRStringStream in = new ANTLRStringStream(actionToken.getText());
+ in.setLine(actionToken.getLine());
+ in.setCharPositionInLine(actionToken.getCharPositionInLine());
+ ActionSplitter splitter = new ActionSplitter(in, this);
+ // forces eval, triggers listener methods
+ node.chunks = splitter.getActionTokens();
+ }
+
+ // LISTENER METHODS
+
+ // $x.y
+ @Override
+ public void qualifiedAttr(String expr, Token x, Token y) {
+ if ( g.isLexer() ) {
+ errMgr.grammarError(ErrorType.ATTRIBUTE_IN_LEXER_ACTION,
+ g.fileName, x, x.getText()+"."+y.getText(), expr);
+ return;
+ }
+ if ( node.resolver.resolveToAttribute(x.getText(), node)!=null ) {
+ // must be a member access to a predefined attribute like $ctx.foo
+ attr(expr, x);
+ return;
+ }
+
+ if ( node.resolver.resolveToAttribute(x.getText(), y.getText(), node)==null ) {
+ Rule rref = isolatedRuleRef(x.getText());
+ if ( rref!=null ) {
+ if ( rref.args!=null && rref.args.get(y.getText())!=null ) {
+ g.tool.errMgr.grammarError(ErrorType.INVALID_RULE_PARAMETER_REF,
+ g.fileName, y, y.getText(), rref.name, expr);
+ }
+ else {
+ errMgr.grammarError(ErrorType.UNKNOWN_RULE_ATTRIBUTE,
+ g.fileName, y, y.getText(), rref.name, expr);
+ }
+ }
+ else if ( !node.resolver.resolvesToAttributeDict(x.getText(), node) ) {
+ errMgr.grammarError(ErrorType.UNKNOWN_SIMPLE_ATTRIBUTE,
+ g.fileName, x, x.getText(), expr);
+ }
+ else {
+ errMgr.grammarError(ErrorType.UNKNOWN_ATTRIBUTE_IN_SCOPE,
+ g.fileName, y, y.getText(), expr);
+ }
+ }
+ }
+
+ @Override
+ public void setAttr(String expr, Token x, Token rhs) {
+ if ( g.isLexer() ) {
+ errMgr.grammarError(ErrorType.ATTRIBUTE_IN_LEXER_ACTION,
+ g.fileName, x, x.getText(), expr);
+ return;
+ }
+ if ( node.resolver.resolveToAttribute(x.getText(), node)==null ) {
+ ErrorType errorType = ErrorType.UNKNOWN_SIMPLE_ATTRIBUTE;
+ if ( node.resolver.resolvesToListLabel(x.getText(), node) ) {
+ // $ids for ids+=ID etc...
+ errorType = ErrorType.ASSIGNMENT_TO_LIST_LABEL;
+ }
+
+ errMgr.grammarError(errorType,
+ g.fileName, x, x.getText(), expr);
+ }
+ new AttributeChecks(g, r, alt, node, rhs).examineAction();
+ }
+
+ @Override
+ public void attr(String expr, Token x) {
+ if ( g.isLexer() ) {
+ errMgr.grammarError(ErrorType.ATTRIBUTE_IN_LEXER_ACTION,
+ g.fileName, x, x.getText(), expr);
+ return;
+ }
+ if ( node.resolver.resolveToAttribute(x.getText(), node)==null ) {
+ if ( node.resolver.resolvesToToken(x.getText(), node) ) {
+ return; // $ID for token ref or label of token
+ }
+ if ( node.resolver.resolvesToListLabel(x.getText(), node) ) {
+ return; // $ids for ids+=ID etc...
+ }
+ if ( isolatedRuleRef(x.getText())!=null ) {
+ errMgr.grammarError(ErrorType.ISOLATED_RULE_REF,
+ g.fileName, x, x.getText(), expr);
+ return;
+ }
+ errMgr.grammarError(ErrorType.UNKNOWN_SIMPLE_ATTRIBUTE,
+ g.fileName, x, x.getText(), expr);
+ }
+ }
+
+ @Override
+ public void nonLocalAttr(String expr, Token x, Token y) {
+ Rule r = g.getRule(x.getText());
+ if ( r==null ) {
+ errMgr.grammarError(ErrorType.UNDEFINED_RULE_IN_NONLOCAL_REF,
+ g.fileName, x, x.getText(), y.getText(), expr);
+ }
+ else if ( r.resolveToAttribute(y.getText(), null)==null ) {
+ errMgr.grammarError(ErrorType.UNKNOWN_RULE_ATTRIBUTE,
+ g.fileName, y, y.getText(), x.getText(), expr);
+
+ }
+ }
+
+ @Override
+ public void setNonLocalAttr(String expr, Token x, Token y, Token rhs) {
+ Rule r = g.getRule(x.getText());
+ if ( r==null ) {
+ errMgr.grammarError(ErrorType.UNDEFINED_RULE_IN_NONLOCAL_REF,
+ g.fileName, x, x.getText(), y.getText(), expr);
+ }
+ else if ( r.resolveToAttribute(y.getText(), null)==null ) {
+ errMgr.grammarError(ErrorType.UNKNOWN_RULE_ATTRIBUTE,
+ g.fileName, y, y.getText(), x.getText(), expr);
+
+ }
+ }
+
+ @Override
+ public void text(String text) { }
+
+ // don't care
+ public void templateInstance(String expr) { }
+ public void indirectTemplateInstance(String expr) { }
+ public void setExprAttribute(String expr) { }
+ public void setSTAttribute(String expr) { }
+ public void templateExpr(String expr) { }
+
+ // SUPPORT
+
+ public Rule isolatedRuleRef(String x) {
+ if ( node.resolver instanceof Grammar ) return null;
+
+ if ( x.equals(r.name) ) return r;
+ List<LabelElementPair> labels = null;
+ if ( node.resolver instanceof Rule ) {
+ labels = r.getElementLabelDefs().get(x);
+ }
+ else if ( node.resolver instanceof Alternative ) {
+ labels = ((Alternative)node.resolver).labelDefs.get(x);
+ }
+ if ( labels!=null ) { // it's a label ref. is it a rule label?
+ LabelElementPair anyLabelDef = labels.get(0);
+ if ( anyLabelDef.type==LabelType.RULE_LABEL ) {
+ return g.getRule(anyLabelDef.element.getText());
+ }
+ }
+ if ( node.resolver instanceof Alternative ) {
+ if ( ((Alternative)node.resolver).ruleRefs.get(x)!=null ) {
+ return g.getRule(x);
+ }
+ }
+ return null;
+ }
+
+}
diff --git a/tool/src/org/antlr/v4/semantics/BasicSemanticChecks.java b/tool/src/org/antlr/v4/semantics/BasicSemanticChecks.java
new file mode 100644
index 0000000..a578a66
--- /dev/null
+++ b/tool/src/org/antlr/v4/semantics/BasicSemanticChecks.java
@@ -0,0 +1,637 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.semantics;
+
+import org.antlr.runtime.Token;
+import org.antlr.runtime.tree.CommonTree;
+import org.antlr.runtime.tree.Tree;
+import org.antlr.v4.misc.Utils;
+import org.antlr.v4.parse.ANTLRParser;
+import org.antlr.v4.parse.GrammarTreeVisitor;
+import org.antlr.v4.tool.ErrorManager;
+import org.antlr.v4.tool.ErrorType;
+import org.antlr.v4.tool.Grammar;
+import org.antlr.v4.tool.Rule;
+import org.antlr.v4.tool.ast.ActionAST;
+import org.antlr.v4.tool.ast.AltAST;
+import org.antlr.v4.tool.ast.BlockAST;
+import org.antlr.v4.tool.ast.GrammarAST;
+import org.antlr.v4.tool.ast.GrammarASTWithOptions;
+import org.antlr.v4.tool.ast.GrammarRootAST;
+import org.antlr.v4.tool.ast.RuleAST;
+import org.antlr.v4.tool.ast.RuleRefAST;
+import org.antlr.v4.tool.ast.TerminalAST;
+import org.stringtemplate.v4.misc.MultiMap;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+/** No side-effects except for setting options into the appropriate node.
+ * TODO: make the side effects into a separate pass this
+ *
+ * Invokes check rules for these:
+ *
+ * FILE_AND_GRAMMAR_NAME_DIFFER
+ * LEXER_RULES_NOT_ALLOWED
+ * PARSER_RULES_NOT_ALLOWED
+ * CANNOT_ALIAS_TOKENS
+ * ARGS_ON_TOKEN_REF
+ * ILLEGAL_OPTION
+ * REWRITE_OR_OP_WITH_NO_OUTPUT_OPTION
+ * NO_RULES
+ * REWRITE_FOR_MULTI_ELEMENT_ALT
+ * HETERO_ILLEGAL_IN_REWRITE_ALT
+ * AST_OP_WITH_NON_AST_OUTPUT_OPTION
+ * AST_OP_IN_ALT_WITH_REWRITE
+ * CONFLICTING_OPTION_IN_TREE_FILTER
+ * WILDCARD_AS_ROOT
+ * INVALID_IMPORT
+ * TOKEN_VOCAB_IN_DELEGATE
+ * IMPORT_NAME_CLASH
+ * REPEATED_PREQUEL
+ * TOKEN_NAMES_MUST_START_UPPER
+ */
+public class BasicSemanticChecks extends GrammarTreeVisitor {
+ /** Set of valid imports. Maps delegate to set of delegator grammar types.
+ * validDelegations.get(LEXER) gives list of the kinds of delegators
+ * that can import lexers.
+ */
+ public static MultiMap<Integer,Integer> validImportTypes =
+ new MultiMap<Integer,Integer>() {
+ {
+ map(ANTLRParser.LEXER, ANTLRParser.LEXER);
+ map(ANTLRParser.LEXER, ANTLRParser.COMBINED);
+
+ map(ANTLRParser.PARSER, ANTLRParser.PARSER);
+ map(ANTLRParser.PARSER, ANTLRParser.COMBINED);
+
+ map(ANTLRParser.COMBINED, ANTLRParser.COMBINED);
+ }
+ };
+
+ public Grammar g;
+ public RuleCollector ruleCollector;
+ public ErrorManager errMgr;
+
+ /**
+ * When this is {@code true}, the semantic checks will report
+ * {@link ErrorType#UNRECOGNIZED_ASSOC_OPTION} where appropriate. This may
+ * be set to {@code false} to disable this specific check.
+ *
+ * <p>The default value is {@code true}.</p>
+ */
+ public boolean checkAssocElementOption = true;
+
+ /**
+ * This field is used for reporting the {@link ErrorType#MODE_WITHOUT_RULES}
+ * error when necessary.
+ */
+ protected int nonFragmentRuleCount;
+
+ /**
+ * This is {@code true} from the time {@link #discoverLexerRule} is called
+ * for a lexer rule with the {@code fragment} modifier until
+ * {@link #exitLexerRule} is called.
+ */
+ private boolean inFragmentRule;
+
+ public BasicSemanticChecks(Grammar g, RuleCollector ruleCollector) {
+ this.g = g;
+ this.ruleCollector = ruleCollector;
+ this.errMgr = g.tool.errMgr;
+ }
+
+ @Override
+ public ErrorManager getErrorManager() { return errMgr; }
+
+ public void process() { visitGrammar(g.ast); }
+
+ // Routines to route visitor traffic to the checking routines
+
+ @Override
+ public void discoverGrammar(GrammarRootAST root, GrammarAST ID) {
+ checkGrammarName(ID.token);
+ }
+
+ @Override
+ public void finishPrequels(GrammarAST firstPrequel) {
+ if ( firstPrequel==null ) return;
+ GrammarAST parent = (GrammarAST)firstPrequel.parent;
+ List<GrammarAST> options = parent.getAllChildrenWithType(OPTIONS);
+ List<GrammarAST> imports = parent.getAllChildrenWithType(IMPORT);
+ List<GrammarAST> tokens = parent.getAllChildrenWithType(TOKENS_SPEC);
+ checkNumPrequels(options, imports, tokens);
+ }
+
+ @Override
+ public void importGrammar(GrammarAST label, GrammarAST ID) {
+ checkImport(ID.token);
+ }
+
+ @Override
+ public void discoverRules(GrammarAST rules) {
+ checkNumRules(rules);
+ }
+
+ @Override
+ protected void enterMode(GrammarAST tree) {
+ nonFragmentRuleCount = 0;
+ }
+
+ @Override
+ protected void exitMode(GrammarAST tree) {
+ if (nonFragmentRuleCount == 0) {
+ Token token = tree.getToken();
+ String name = "?";
+ if (tree.getChildCount() > 0) {
+ name = tree.getChild(0).getText();
+ if (name == null || name.isEmpty()) {
+ name = "?";
+ }
+
+ token = ((GrammarAST)tree.getChild(0)).getToken();
+ }
+
+ g.tool.errMgr.grammarError(ErrorType.MODE_WITHOUT_RULES, g.fileName, token, name, g);
+ }
+ }
+
+ @Override
+ public void modeDef(GrammarAST m, GrammarAST ID) {
+ if ( !g.isLexer() ) {
+ g.tool.errMgr.grammarError(ErrorType.MODE_NOT_IN_LEXER, g.fileName,
+ ID.token, ID.token.getText(), g);
+ }
+ }
+
+ @Override
+ public void discoverRule(RuleAST rule, GrammarAST ID,
+ List<GrammarAST> modifiers,
+ ActionAST arg, ActionAST returns,
+ GrammarAST thrws, GrammarAST options,
+ ActionAST locals,
+ List<GrammarAST> actions, GrammarAST block)
+ {
+ // TODO: chk that all or no alts have "# label"
+ checkInvalidRuleDef(ID.token);
+ }
+
+ @Override
+ public void discoverLexerRule(RuleAST rule, GrammarAST ID, List<GrammarAST> modifiers,
+ GrammarAST block)
+ {
+ checkInvalidRuleDef(ID.token);
+
+ if (modifiers != null) {
+ for (GrammarAST tree : modifiers) {
+ if (tree.getType() == ANTLRParser.FRAGMENT) {
+ inFragmentRule = true;
+ }
+ }
+ }
+
+ if (!inFragmentRule) {
+ nonFragmentRuleCount++;
+ }
+ }
+
+ @Override
+ protected void exitLexerRule(GrammarAST tree) {
+ inFragmentRule = false;
+ }
+
+ @Override
+ public void ruleRef(GrammarAST ref, ActionAST arg) {
+ checkInvalidRuleRef(ref.token);
+ }
+
+ @Override
+ public void ruleOption(GrammarAST ID, GrammarAST valueAST) {
+ checkOptions((GrammarAST)ID.getAncestor(RULE), ID.token, valueAST);
+ }
+
+ @Override
+ public void blockOption(GrammarAST ID, GrammarAST valueAST) {
+ checkOptions((GrammarAST)ID.getAncestor(BLOCK), ID.token, valueAST);
+ }
+
+ @Override
+ public void grammarOption(GrammarAST ID, GrammarAST valueAST) {
+ boolean ok = checkOptions(g.ast, ID.token, valueAST);
+ //if ( ok ) g.ast.setOption(ID.getText(), value);
+ }
+
+ @Override
+ public void defineToken(GrammarAST ID) {
+ checkTokenDefinition(ID.token);
+ }
+
+ @Override
+ protected void enterChannelsSpec(GrammarAST tree) {
+ if (g.isParser()) {
+ g.tool.errMgr.grammarError(ErrorType.CHANNELS_BLOCK_IN_PARSER_GRAMMAR, g.fileName, tree.token);
+ }
+ else if (g.isCombined()) {
+ g.tool.errMgr.grammarError(ErrorType.CHANNELS_BLOCK_IN_COMBINED_GRAMMAR, g.fileName, tree.token);
+ }
+ }
+
+ @Override
+ public void defineChannel(GrammarAST ID) {
+ checkChannelDefinition(ID.token);
+ }
+
+ @Override
+ public void elementOption(GrammarASTWithOptions elem, GrammarAST ID, GrammarAST valueAST) {
+ String v = null;
+ boolean ok = checkElementOptions(elem, ID, valueAST);
+// if ( ok ) {
+// if ( v!=null ) {
+// t.setOption(ID.getText(), v);
+// }
+// else {
+// t.setOption(TerminalAST.defaultTokenOption, v);
+// }
+// }
+ }
+
+ @Override
+ public void finishRule(RuleAST rule, GrammarAST ID, GrammarAST block) {
+ if ( rule.isLexerRule() ) return;
+ BlockAST blk = (BlockAST)rule.getFirstChildWithType(BLOCK);
+ int nalts = blk.getChildCount();
+ GrammarAST idAST = (GrammarAST)rule.getChild(0);
+ for (int i=0; i< nalts; i++) {
+ AltAST altAST = (AltAST)blk.getChild(i);
+ if ( altAST.altLabel!=null ) {
+ String altLabel = altAST.altLabel.getText();
+ // first check that label doesn't conflict with a rule
+ // label X or x can't be rule x.
+ Rule r = ruleCollector.rules.get(Utils.decapitalize(altLabel));
+ if ( r!=null ) {
+ g.tool.errMgr.grammarError(ErrorType.ALT_LABEL_CONFLICTS_WITH_RULE,
+ g.fileName, altAST.altLabel.token,
+ altLabel,
+ r.name);
+ }
+ // Now verify that label X or x doesn't conflict with label
+ // in another rule. altLabelToRuleName has both X and x mapped.
+ String prevRuleForLabel = ruleCollector.altLabelToRuleName.get(altLabel);
+ if ( prevRuleForLabel!=null && !prevRuleForLabel.equals(rule.getRuleName()) ) {
+ g.tool.errMgr.grammarError(ErrorType.ALT_LABEL_REDEF,
+ g.fileName, altAST.altLabel.token,
+ altLabel,
+ rule.getRuleName(),
+ prevRuleForLabel);
+ }
+ }
+ }
+ List<GrammarAST> altLabels = ruleCollector.ruleToAltLabels.get(rule.getRuleName());
+ int numAltLabels = 0;
+ if ( altLabels!=null ) numAltLabels = altLabels.size();
+ if ( numAltLabels>0 && nalts != numAltLabels ) {
+ g.tool.errMgr.grammarError(ErrorType.RULE_WITH_TOO_FEW_ALT_LABELS,
+ g.fileName, idAST.token, rule.getRuleName());
+ }
+ }
+
+ // Routines to do the actual work of checking issues with a grammar.
+ // They are triggered by the visitor methods above.
+
+ void checkGrammarName(Token nameToken) {
+ String fullyQualifiedName = nameToken.getInputStream().getSourceName();
+ if (fullyQualifiedName == null) {
+ // This wasn't read from a file.
+ return;
+ }
+
+ File f = new File(fullyQualifiedName);
+ String fileName = f.getName();
+ if ( g.originalGrammar!=null ) return; // don't warn about diff if this is implicit lexer
+ if ( !Utils.stripFileExtension(fileName).equals(nameToken.getText()) &&
+ !fileName.equals(Grammar.GRAMMAR_FROM_STRING_NAME)) {
+ g.tool.errMgr.grammarError(ErrorType.FILE_AND_GRAMMAR_NAME_DIFFER,
+ fileName, nameToken, nameToken.getText(), fileName);
+ }
+ }
+
+ void checkNumRules(GrammarAST rulesNode) {
+ if ( rulesNode.getChildCount()==0 ) {
+ GrammarAST root = (GrammarAST)rulesNode.getParent();
+ GrammarAST IDNode = (GrammarAST)root.getChild(0);
+ g.tool.errMgr.grammarError(ErrorType.NO_RULES, g.fileName,
+ null, IDNode.getText(), g);
+ }
+ }
+
+ void checkNumPrequels(List<GrammarAST> options,
+ List<GrammarAST> imports,
+ List<GrammarAST> tokens)
+ {
+ List<Token> secondOptionTokens = new ArrayList<Token>();
+ if ( options!=null && options.size()>1 ) {
+ secondOptionTokens.add(options.get(1).token);
+ }
+ if ( imports!=null && imports.size()>1 ) {
+ secondOptionTokens.add(imports.get(1).token);
+ }
+ if ( tokens!=null && tokens.size()>1 ) {
+ secondOptionTokens.add(tokens.get(1).token);
+ }
+ for (Token t : secondOptionTokens) {
+ String fileName = t.getInputStream().getSourceName();
+ g.tool.errMgr.grammarError(ErrorType.REPEATED_PREQUEL,
+ fileName, t);
+ }
+ }
+
+ void checkInvalidRuleDef(Token ruleID) {
+ String fileName = null;
+ if ( ruleID.getInputStream()!=null ) {
+ fileName = ruleID.getInputStream().getSourceName();
+ }
+ if ( g.isLexer() && Character.isLowerCase(ruleID.getText().charAt(0)) ) {
+ g.tool.errMgr.grammarError(ErrorType.PARSER_RULES_NOT_ALLOWED,
+ fileName, ruleID, ruleID.getText());
+ }
+ if ( g.isParser() &&
+ Grammar.isTokenName(ruleID.getText()) )
+ {
+ g.tool.errMgr.grammarError(ErrorType.LEXER_RULES_NOT_ALLOWED,
+ fileName, ruleID, ruleID.getText());
+ }
+ }
+
+ void checkInvalidRuleRef(Token ruleID) {
+ String fileName = ruleID.getInputStream().getSourceName();
+ if ( g.isLexer() && Character.isLowerCase(ruleID.getText().charAt(0)) ) {
+ g.tool.errMgr.grammarError(ErrorType.PARSER_RULE_REF_IN_LEXER_RULE,
+ fileName, ruleID, ruleID.getText(), currentRuleName);
+ }
+ }
+
+ void checkTokenDefinition(Token tokenID) {
+ String fileName = tokenID.getInputStream().getSourceName();
+ if ( !Grammar.isTokenName(tokenID.getText()) ) {
+ g.tool.errMgr.grammarError(ErrorType.TOKEN_NAMES_MUST_START_UPPER,
+ fileName,
+ tokenID,
+ tokenID.getText());
+ }
+ }
+
+ void checkChannelDefinition(Token tokenID) {
+ }
+
+ @Override
+ protected void enterLexerElement(GrammarAST tree) {
+ }
+
+ @Override
+ protected void enterLexerCommand(GrammarAST tree) {
+ checkElementIsOuterMostInSingleAlt(tree);
+
+ if (inFragmentRule) {
+ String fileName = tree.token.getInputStream().getSourceName();
+ String ruleName = currentRuleName;
+ g.tool.errMgr.grammarError(ErrorType.FRAGMENT_ACTION_IGNORED, fileName, tree.token, ruleName);
+ }
+ }
+
+ @Override
+ public void actionInAlt(ActionAST action) {
+ if (inFragmentRule) {
+ String fileName = action.token.getInputStream().getSourceName();
+ String ruleName = currentRuleName;
+ g.tool.errMgr.grammarError(ErrorType.FRAGMENT_ACTION_IGNORED, fileName, action.token, ruleName);
+ }
+ }
+
+ /**
+ Make sure that action is last element in outer alt; here action,
+ a2, z, and zz are bad, but a3 is ok:
+ (RULE A (BLOCK (ALT {action} 'a')))
+ (RULE B (BLOCK (ALT (BLOCK (ALT {a2} 'x') (ALT 'y')) {a3})))
+ (RULE C (BLOCK (ALT 'd' {z}) (ALT 'e' {zz})))
+ */
+ protected void checkElementIsOuterMostInSingleAlt(GrammarAST tree) {
+ CommonTree alt = tree.parent;
+ CommonTree blk = alt.parent;
+ boolean outerMostAlt = blk.parent.getType() == RULE;
+ Tree rule = tree.getAncestor(RULE);
+ String fileName = tree.getToken().getInputStream().getSourceName();
+ if ( !outerMostAlt || blk.getChildCount()>1 )
+ {
+ ErrorType e = ErrorType.LEXER_COMMAND_PLACEMENT_ISSUE;
+ g.tool.errMgr.grammarError(e,
+ fileName,
+ tree.getToken(),
+ rule.getChild(0).getText());
+
+ }
+ }
+
+ @Override
+ public void label(GrammarAST op, GrammarAST ID, GrammarAST element) {
+ switch (element.getType()) {
+ // token atoms
+ case TOKEN_REF:
+ case STRING_LITERAL:
+ case RANGE:
+ // token sets
+ case SET:
+ case NOT:
+ // rule atoms
+ case RULE_REF:
+ case WILDCARD:
+ return;
+
+ default:
+ String fileName = ID.token.getInputStream().getSourceName();
+ g.tool.errMgr.grammarError(ErrorType.LABEL_BLOCK_NOT_A_SET, fileName, ID.token, ID.getText());
+ break;
+ }
+ }
+
+ @Override
+ protected void enterLabeledLexerElement(GrammarAST tree) {
+ Token label = ((GrammarAST)tree.getChild(0)).getToken();
+ g.tool.errMgr.grammarError(ErrorType.V3_LEXER_LABEL,
+ g.fileName,
+ label,
+ label.getText());
+ }
+
+ /** Check option is appropriate for grammar, rule, subrule */
+ boolean checkOptions(GrammarAST parent,
+ Token optionID,
+ GrammarAST valueAST)
+ {
+ boolean ok = true;
+ if ( parent.getType()==ANTLRParser.BLOCK ) {
+ if ( g.isLexer() && !Grammar.LexerBlockOptions.contains(optionID.getText()) ) { // block
+ g.tool.errMgr.grammarError(ErrorType.ILLEGAL_OPTION,
+ g.fileName,
+ optionID,
+ optionID.getText());
+ ok = false;
+ }
+ if ( !g.isLexer() && !Grammar.ParserBlockOptions.contains(optionID.getText()) ) { // block
+ g.tool.errMgr.grammarError(ErrorType.ILLEGAL_OPTION,
+ g.fileName,
+ optionID,
+ optionID.getText());
+ ok = false;
+ }
+ }
+ else if ( parent.getType()==ANTLRParser.RULE ) {
+ if ( !Grammar.ruleOptions.contains(optionID.getText()) ) { // rule
+ g.tool.errMgr.grammarError(ErrorType.ILLEGAL_OPTION,
+ g.fileName,
+ optionID,
+ optionID.getText());
+ ok = false;
+ }
+ }
+ else if ( parent.getType()==ANTLRParser.GRAMMAR &&
+ !legalGrammarOption(optionID.getText()) ) { // grammar
+ g.tool.errMgr.grammarError(ErrorType.ILLEGAL_OPTION,
+ g.fileName,
+ optionID,
+ optionID.getText());
+ ok = false;
+ }
+
+ return ok;
+ }
+
+ /** Check option is appropriate for elem; parent of ID is ELEMENT_OPTIONS */
+ boolean checkElementOptions(GrammarASTWithOptions elem,
+ GrammarAST ID,
+ GrammarAST valueAST)
+ {
+ if (checkAssocElementOption && ID != null && "assoc".equals(ID.getText())) {
+ if (elem.getType() != ANTLRParser.ALT) {
+ Token optionID = ID.token;
+ String fileName = optionID.getInputStream().getSourceName();
+ g.tool.errMgr.grammarError(ErrorType.UNRECOGNIZED_ASSOC_OPTION,
+ fileName,
+ optionID,
+ currentRuleName);
+ }
+ }
+
+ if ( elem instanceof RuleRefAST ) {
+ return checkRuleRefOptions((RuleRefAST)elem, ID, valueAST);
+ }
+ if ( elem instanceof TerminalAST ) {
+ return checkTokenOptions((TerminalAST)elem, ID, valueAST);
+ }
+ if ( elem.getType()==ANTLRParser.ACTION ) {
+ return false;
+ }
+ if ( elem.getType()==ANTLRParser.SEMPRED ) {
+ Token optionID = ID.token;
+ String fileName = optionID.getInputStream().getSourceName();
+ if ( valueAST!=null && !Grammar.semPredOptions.contains(optionID.getText()) ) {
+ g.tool.errMgr.grammarError(ErrorType.ILLEGAL_OPTION,
+ fileName,
+ optionID,
+ optionID.getText());
+ return false;
+ }
+ }
+ return false;
+ }
+
+ boolean checkRuleRefOptions(RuleRefAST elem, GrammarAST ID, GrammarAST valueAST) {
+ Token optionID = ID.token;
+ String fileName = optionID.getInputStream().getSourceName();
+ // don't care about id<SimpleValue> options
+ if ( valueAST!=null && !Grammar.ruleRefOptions.contains(optionID.getText()) ) {
+ g.tool.errMgr.grammarError(ErrorType.ILLEGAL_OPTION,
+ fileName,
+ optionID,
+ optionID.getText());
+ return false;
+ }
+ // TODO: extra checks depending on rule kind?
+ return true;
+ }
+
+ boolean checkTokenOptions(TerminalAST elem, GrammarAST ID, GrammarAST valueAST) {
+ Token optionID = ID.token;
+ String fileName = optionID.getInputStream().getSourceName();
+ // don't care about ID<ASTNodeName> options
+ if ( valueAST!=null && !Grammar.tokenOptions.contains(optionID.getText()) ) {
+ g.tool.errMgr.grammarError(ErrorType.ILLEGAL_OPTION,
+ fileName,
+ optionID,
+ optionID.getText());
+ return false;
+ }
+ // TODO: extra checks depending on terminal kind?
+ return true;
+ }
+
+ boolean legalGrammarOption(String key) {
+ switch ( g.getType() ) {
+ case ANTLRParser.LEXER :
+ return Grammar.lexerOptions.contains(key);
+ case ANTLRParser.PARSER :
+ return Grammar.parserOptions.contains(key);
+ default :
+ return Grammar.parserOptions.contains(key);
+ }
+ }
+
+ void checkImport(Token importID) {
+ Grammar delegate = g.getImportedGrammar(importID.getText());
+ if ( delegate==null ) return;
+ List<Integer> validDelegators = validImportTypes.get(delegate.getType());
+ if ( validDelegators!=null && !validDelegators.contains(g.getType()) ) {
+ g.tool.errMgr.grammarError(ErrorType.INVALID_IMPORT,
+ g.fileName,
+ importID,
+ g, delegate);
+ }
+ if ( g.isCombined() &&
+ (delegate.name.equals(g.name+Grammar.getGrammarTypeToFileNameSuffix(ANTLRParser.LEXER))||
+ delegate.name.equals(g.name+Grammar.getGrammarTypeToFileNameSuffix(ANTLRParser.PARSER))) )
+ {
+ g.tool.errMgr.grammarError(ErrorType.IMPORT_NAME_CLASH,
+ g.fileName,
+ importID,
+ g, delegate);
+ }
+ }
+}
diff --git a/tool/src/org/antlr/v4/semantics/BlankActionSplitterListener.java b/tool/src/org/antlr/v4/semantics/BlankActionSplitterListener.java
new file mode 100644
index 0000000..e919890
--- /dev/null
+++ b/tool/src/org/antlr/v4/semantics/BlankActionSplitterListener.java
@@ -0,0 +1,75 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.semantics;
+
+import org.antlr.runtime.Token;
+import org.antlr.v4.parse.ActionSplitterListener;
+
+public class BlankActionSplitterListener implements ActionSplitterListener {
+ @Override
+ public void qualifiedAttr(String expr, Token x, Token y) {
+ }
+
+ @Override
+ public void setAttr(String expr, Token x, Token rhs) {
+ }
+
+ @Override
+ public void attr(String expr, Token x) {
+ }
+
+ public void templateInstance(String expr) {
+ }
+
+ @Override
+ public void nonLocalAttr(String expr, Token x, Token y) {
+ }
+
+ @Override
+ public void setNonLocalAttr(String expr, Token x, Token y, Token rhs) {
+ }
+
+ public void indirectTemplateInstance(String expr) {
+ }
+
+ public void setExprAttribute(String expr) {
+ }
+
+ public void setSTAttribute(String expr) {
+ }
+
+ public void templateExpr(String expr) {
+ }
+
+ @Override
+ public void text(String text) {
+ }
+}
diff --git a/tool/src/org/antlr/v4/semantics/RuleCollector.java b/tool/src/org/antlr/v4/semantics/RuleCollector.java
new file mode 100644
index 0000000..fa7eb2d
--- /dev/null
+++ b/tool/src/org/antlr/v4/semantics/RuleCollector.java
@@ -0,0 +1,138 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.semantics;
+
+import org.antlr.v4.analysis.LeftRecursiveRuleAnalyzer;
+import org.antlr.v4.misc.OrderedHashMap;
+import org.antlr.v4.misc.Utils;
+import org.antlr.v4.parse.GrammarTreeVisitor;
+import org.antlr.v4.parse.ScopeParser;
+import org.antlr.v4.tool.AttributeDict;
+import org.antlr.v4.tool.ErrorManager;
+import org.antlr.v4.tool.Grammar;
+import org.antlr.v4.tool.LeftRecursiveRule;
+import org.antlr.v4.tool.Rule;
+import org.antlr.v4.tool.ast.ActionAST;
+import org.antlr.v4.tool.ast.AltAST;
+import org.antlr.v4.tool.ast.GrammarAST;
+import org.antlr.v4.tool.ast.RuleAST;
+import org.stringtemplate.v4.misc.MultiMap;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class RuleCollector extends GrammarTreeVisitor {
+ /** which grammar are we checking */
+ public Grammar g;
+ public ErrorManager errMgr;
+
+ // stuff to collect. this is the output
+ public OrderedHashMap<String, Rule> rules = new OrderedHashMap<String, Rule>();
+ public MultiMap<String,GrammarAST> ruleToAltLabels = new MultiMap<String, GrammarAST>();
+ public Map<String,String> altLabelToRuleName = new HashMap<String, String>();
+
+ public RuleCollector(Grammar g) {
+ this.g = g;
+ this.errMgr = g.tool.errMgr;
+ }
+
+ @Override
+ public ErrorManager getErrorManager() { return errMgr; }
+
+ public void process(GrammarAST ast) { visitGrammar(ast); }
+
+ @Override
+ public void discoverRule(RuleAST rule, GrammarAST ID,
+ List<GrammarAST> modifiers, ActionAST arg,
+ ActionAST returns, GrammarAST thrws,
+ GrammarAST options, ActionAST locals,
+ List<GrammarAST> actions,
+ GrammarAST block)
+ {
+ int numAlts = block.getChildCount();
+ Rule r;
+ if ( LeftRecursiveRuleAnalyzer.hasImmediateRecursiveRuleRefs(rule, ID.getText()) ) {
+ r = new LeftRecursiveRule(g, ID.getText(), rule);
+ }
+ else {
+ r = new Rule(g, ID.getText(), rule, numAlts);
+ }
+ rules.put(r.name, r);
+
+ if ( arg!=null ) {
+ r.args = ScopeParser.parseTypedArgList(arg, arg.getText(), g);
+ r.args.type = AttributeDict.DictType.ARG;
+ r.args.ast = arg;
+ arg.resolver = r.alt[currentOuterAltNumber];
+ }
+
+ if ( returns!=null ) {
+ r.retvals = ScopeParser.parseTypedArgList(returns, returns.getText(), g);
+ r.retvals.type = AttributeDict.DictType.RET;
+ r.retvals.ast = returns;
+ }
+
+ if ( locals!=null ) {
+ r.locals = ScopeParser.parseTypedArgList(locals, locals.getText(), g);
+ r.locals.type = AttributeDict.DictType.LOCAL;
+ r.locals.ast = locals;
+ }
+
+ for (GrammarAST a : actions) {
+ // a = ^(AT ID ACTION)
+ ActionAST action = (ActionAST) a.getChild(1);
+ r.namedActions.put(a.getChild(0).getText(), action);
+ action.resolver = r;
+ }
+ }
+
+ @Override
+ public void discoverOuterAlt(AltAST alt) {
+ if ( alt.altLabel!=null ) {
+ ruleToAltLabels.map(currentRuleName, alt.altLabel);
+ String altLabel = alt.altLabel.getText();
+ altLabelToRuleName.put(Utils.capitalize(altLabel), currentRuleName);
+ altLabelToRuleName.put(Utils.decapitalize(altLabel), currentRuleName);
+ }
+ }
+
+ @Override
+ public void discoverLexerRule(RuleAST rule, GrammarAST ID, List<GrammarAST> modifiers,
+ GrammarAST block)
+ {
+ int numAlts = block.getChildCount();
+ Rule r = new Rule(g, ID.getText(), rule, numAlts);
+ r.mode = currentModeName;
+ if ( !modifiers.isEmpty() ) r.modifiers = modifiers;
+ rules.put(r.name, r);
+ }
+}
diff --git a/tool/src/org/antlr/v4/semantics/SemanticPipeline.java b/tool/src/org/antlr/v4/semantics/SemanticPipeline.java
new file mode 100644
index 0000000..3561f91
--- /dev/null
+++ b/tool/src/org/antlr/v4/semantics/SemanticPipeline.java
@@ -0,0 +1,300 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.semantics;
+
+import org.antlr.v4.analysis.LeftRecursiveRuleTransformer;
+import org.antlr.v4.parse.ANTLRParser;
+import org.antlr.v4.runtime.Token;
+import org.antlr.v4.runtime.misc.Pair;
+import org.antlr.v4.tool.ErrorType;
+import org.antlr.v4.tool.Grammar;
+import org.antlr.v4.tool.LexerGrammar;
+import org.antlr.v4.tool.Rule;
+import org.antlr.v4.tool.ast.GrammarAST;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/** Do as much semantic checking as we can and fill in grammar
+ * with rules, actions, and token definitions.
+ * The only side effects are in the grammar passed to process().
+ * We consume a bunch of memory here while we build up data structures
+ * to perform checking, but all of it goes away after this pipeline object
+ * gets garbage collected.
+ *
+ * After this pipeline finishes, we can be sure that the grammar
+ * is syntactically correct and that it's semantically correct enough for us
+ * to attempt grammar analysis. We have assigned all token types.
+ * Note that imported grammars bring in token and rule definitions
+ * but only the root grammar and any implicitly created lexer grammar
+ * get their token definitions filled up. We are treating the
+ * imported grammars like includes.
+ *
+ * The semantic pipeline works on root grammars (those that do the importing,
+ * if any). Upon entry to the semantic pipeline, all imported grammars
+ * should have been loaded into delegate grammar objects with their
+ * ASTs created. The pipeline does the BasicSemanticChecks on the
+ * imported grammar before collecting symbols. We cannot perform the
+ * simple checks such as undefined rule until we have collected all
+ * tokens and rules from the imported grammars into a single collection.
+ */
+public class SemanticPipeline {
+ public Grammar g;
+
+ public SemanticPipeline(Grammar g) {
+ this.g = g;
+ }
+
+ public void process() {
+ if ( g.ast==null ) return;
+
+ // COLLECT RULE OBJECTS
+ RuleCollector ruleCollector = new RuleCollector(g);
+ ruleCollector.process(g.ast);
+
+ // DO BASIC / EASY SEMANTIC CHECKS
+ BasicSemanticChecks basics = new BasicSemanticChecks(g, ruleCollector);
+ basics.process();
+
+ // TRANSFORM LEFT-RECURSIVE RULES
+ int prevErrors = g.tool.errMgr.getNumErrors();
+ LeftRecursiveRuleTransformer lrtrans =
+ new LeftRecursiveRuleTransformer(g.ast, ruleCollector.rules.values(), g);
+ lrtrans.translateLeftRecursiveRules();
+
+ // don't continue if we got errors during left-recursion elimination
+ if ( g.tool.errMgr.getNumErrors()>prevErrors ) return;
+
+ // STORE RULES IN GRAMMAR
+ for (Rule r : ruleCollector.rules.values()) {
+ g.defineRule(r);
+ }
+
+ // COLLECT SYMBOLS: RULES, ACTIONS, TERMINALS, ...
+ SymbolCollector collector = new SymbolCollector(g);
+ collector.process(g.ast);
+
+ // CHECK FOR SYMBOL COLLISIONS
+ SymbolChecks symcheck = new SymbolChecks(g, collector);
+ symcheck.process(); // side-effect: strip away redef'd rules.
+
+ for (GrammarAST a : collector.namedActions) {
+ g.defineAction(a);
+ }
+
+ // LINK (outermost) ALT NODES WITH Alternatives
+ for (Rule r : g.rules.values()) {
+ for (int i=1; i<=r.numberOfAlts; i++) {
+ r.alt[i].ast.alt = r.alt[i];
+ }
+ }
+
+ // ASSIGN TOKEN TYPES
+ g.importTokensFromTokensFile();
+ if ( g.isLexer() ) {
+ assignLexerTokenTypes(g, collector.tokensDefs);
+ }
+ else {
+ assignTokenTypes(g, collector.tokensDefs,
+ collector.tokenIDRefs, collector.terminals);
+ }
+
+ assignChannelTypes(g, collector.channelDefs);
+
+ // CHECK RULE REFS NOW (that we've defined rules in grammar)
+ symcheck.checkRuleArgs(g, collector.rulerefs);
+ identifyStartRules(collector);
+ symcheck.checkForQualifiedRuleIssues(g, collector.qualifiedRulerefs);
+
+ // don't continue if we got symbol errors
+ if ( g.tool.getNumErrors()>0 ) return;
+
+ // CHECK ATTRIBUTE EXPRESSIONS FOR SEMANTIC VALIDITY
+ AttributeChecks.checkAllAttributeExpressions(g);
+
+ UseDefAnalyzer.trackTokenRuleRefsInActions(g);
+ }
+
+ void identifyStartRules(SymbolCollector collector) {
+ for (GrammarAST ref : collector.rulerefs) {
+ String ruleName = ref.getText();
+ Rule r = g.getRule(ruleName);
+ if ( r!=null ) r.isStartRule = false;
+ }
+ }
+
+ void assignLexerTokenTypes(Grammar g, List<GrammarAST> tokensDefs) {
+ Grammar G = g.getOutermostGrammar(); // put in root, even if imported
+ for (GrammarAST def : tokensDefs) {
+ // tokens { id (',' id)* } so must check IDs not TOKEN_REF
+ if ( Grammar.isTokenName(def.getText()) ) {
+ G.defineTokenName(def.getText());
+ }
+ }
+
+ /* Define token types for nonfragment rules which do not include a 'type(...)'
+ * or 'more' lexer command.
+ */
+ for (Rule r : g.rules.values()) {
+ if ( !r.isFragment() && !hasTypeOrMoreCommand(r) ) {
+ G.defineTokenName(r.name);
+ }
+ }
+
+ // FOR ALL X : 'xxx'; RULES, DEFINE 'xxx' AS TYPE X
+ List<Pair<GrammarAST,GrammarAST>> litAliases =
+ Grammar.getStringLiteralAliasesFromLexerRules(g.ast);
+ Set<String> conflictingLiterals = new HashSet<String>();
+ if ( litAliases!=null ) {
+ for (Pair<GrammarAST,GrammarAST> pair : litAliases) {
+ GrammarAST nameAST = pair.a;
+ GrammarAST litAST = pair.b;
+ if ( !G.stringLiteralToTypeMap.containsKey(litAST.getText()) ) {
+ G.defineTokenAlias(nameAST.getText(), litAST.getText());
+ }
+ else {
+ // oops two literal defs in two rules (within or across modes).
+ conflictingLiterals.add(litAST.getText());
+ }
+ }
+ for (String lit : conflictingLiterals) {
+ // Remove literal if repeated across rules so it's not
+ // found by parser grammar.
+ Integer value = G.stringLiteralToTypeMap.remove(lit);
+ if (value != null && value > 0 && value < G.typeToStringLiteralList.size() && lit.equals(G.typeToStringLiteralList.get(value))) {
+ G.typeToStringLiteralList.set(value, null);
+ }
+ }
+ }
+
+ }
+
+ boolean hasTypeOrMoreCommand(Rule r) {
+ GrammarAST ast = r.ast;
+ if (ast == null) {
+ return false;
+ }
+
+ GrammarAST altActionAst = (GrammarAST)ast.getFirstDescendantWithType(ANTLRParser.LEXER_ALT_ACTION);
+ if (altActionAst == null) {
+ // the rule isn't followed by any commands
+ return false;
+ }
+
+ // first child is the alt itself, subsequent are the actions
+ for (int i = 1; i < altActionAst.getChildCount(); i++) {
+ GrammarAST node = (GrammarAST)altActionAst.getChild(i);
+ if (node.getType() == ANTLRParser.LEXER_ACTION_CALL) {
+ if ("type".equals(node.getChild(0).getText())) {
+ return true;
+ }
+ }
+ else if ("more".equals(node.getText())) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ void assignTokenTypes(Grammar g, List<GrammarAST> tokensDefs,
+ List<GrammarAST> tokenIDs, List<GrammarAST> terminals)
+ {
+ //Grammar G = g.getOutermostGrammar(); // put in root, even if imported
+
+ // create token types for tokens { A, B, C } ALIASES
+ for (GrammarAST alias : tokensDefs) {
+ if (g.getTokenType(alias.getText()) != Token.INVALID_TYPE) {
+ g.tool.errMgr.grammarError(ErrorType.TOKEN_NAME_REASSIGNMENT, g.fileName, alias.token, alias.getText());
+ }
+
+ g.defineTokenName(alias.getText());
+ }
+
+ // DEFINE TOKEN TYPES FOR TOKEN REFS LIKE ID, INT
+ for (GrammarAST idAST : tokenIDs) {
+ if (g.getTokenType(idAST.getText()) == Token.INVALID_TYPE) {
+ g.tool.errMgr.grammarError(ErrorType.IMPLICIT_TOKEN_DEFINITION, g.fileName, idAST.token, idAST.getText());
+ }
+
+ g.defineTokenName(idAST.getText());
+ }
+
+ // VERIFY TOKEN TYPES FOR STRING LITERAL REFS LIKE 'while', ';'
+ for (GrammarAST termAST : terminals) {
+ if (termAST.getType() != ANTLRParser.STRING_LITERAL) {
+ continue;
+ }
+
+ if (g.getTokenType(termAST.getText()) == Token.INVALID_TYPE) {
+ g.tool.errMgr.grammarError(ErrorType.IMPLICIT_STRING_DEFINITION, g.fileName, termAST.token, termAST.getText());
+ }
+ }
+
+ g.tool.log("semantics", "tokens="+g.tokenNameToTypeMap);
+ g.tool.log("semantics", "strings="+g.stringLiteralToTypeMap);
+ }
+
+ /**
+ * Assign constant values to custom channels defined in a grammar.
+ *
+ * @param g The grammar.
+ * @param channelDefs A collection of AST nodes defining individual channels
+ * within a {@code channels{}} block in the grammar.
+ */
+ void assignChannelTypes(Grammar g, List<GrammarAST> channelDefs) {
+ Grammar outermost = g.getOutermostGrammar();
+ for (GrammarAST channel : channelDefs) {
+ String channelName = channel.getText();
+
+ // Channel names can't alias tokens or modes, because constant
+ // values are also assigned to them and the ->channel(NAME) lexer
+ // command does not distinguish between the various ways a constant
+ // can be declared. This method does not verify that channels do not
+ // alias rules, because rule names are not associated with constant
+ // values in ANTLR grammar semantics.
+
+ if (g.getTokenType(channelName) != Token.INVALID_TYPE) {
+ g.tool.errMgr.grammarError(ErrorType.CHANNEL_CONFLICTS_WITH_TOKEN, g.fileName, channel.token, channelName);
+ }
+
+ if (outermost instanceof LexerGrammar) {
+ LexerGrammar lexerGrammar = (LexerGrammar)outermost;
+ if (lexerGrammar.modes.containsKey(channelName)) {
+ g.tool.errMgr.grammarError(ErrorType.CHANNEL_CONFLICTS_WITH_MODE, g.fileName, channel.token, channelName);
+ }
+ }
+
+ outermost.defineChannelName(channel.getText());
+ }
+ }
+}
diff --git a/tool/src/org/antlr/v4/semantics/SymbolChecks.java b/tool/src/org/antlr/v4/semantics/SymbolChecks.java
new file mode 100644
index 0000000..b280f40
--- /dev/null
+++ b/tool/src/org/antlr/v4/semantics/SymbolChecks.java
@@ -0,0 +1,312 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.semantics;
+
+import org.antlr.v4.parse.ANTLRParser;
+import org.antlr.v4.tool.Alternative;
+import org.antlr.v4.tool.Attribute;
+import org.antlr.v4.tool.AttributeDict;
+import org.antlr.v4.tool.ErrorManager;
+import org.antlr.v4.tool.ErrorType;
+import org.antlr.v4.tool.Grammar;
+import org.antlr.v4.tool.LabelElementPair;
+import org.antlr.v4.tool.Rule;
+import org.antlr.v4.tool.ast.GrammarAST;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/** Check for symbol problems; no side-effects. Inefficient to walk rules
+ * and such multiple times, but I like isolating all error checking outside
+ * of code that actually defines symbols etc...
+ *
+ * Side-effect: strip away redef'd rules.
+ */
+public class SymbolChecks {
+ Grammar g;
+ SymbolCollector collector;
+ Map<String, Rule> nameToRuleMap = new HashMap<String, Rule>();
+ Set<String> tokenIDs = new HashSet<String>();
+ Map<String, Set<String>> actionScopeToActionNames = new HashMap<String, Set<String>>();
+// DoubleKeyMap<String, String, GrammarAST> namedActions =
+// new DoubleKeyMap<String, String, GrammarAST>();
+
+ public ErrorManager errMgr;
+
+ protected final Set<String> reservedNames = new HashSet<String>();
+ {
+ reservedNames.add("EOF");
+ }
+
+ public SymbolChecks(Grammar g, SymbolCollector collector) {
+ this.g = g;
+ this.collector = collector;
+ this.errMgr = g.tool.errMgr;
+
+ for (GrammarAST tokenId : collector.tokenIDRefs) {
+ tokenIDs.add(tokenId.getText());
+ }
+ /*
+ System.out.println("rules="+collector.rules);
+ System.out.println("rulerefs="+collector.rulerefs);
+ System.out.println("tokenIDRefs="+collector.tokenIDRefs);
+ System.out.println("terminals="+collector.terminals);
+ System.out.println("strings="+collector.strings);
+ System.out.println("tokensDef="+collector.tokensDefs);
+ System.out.println("actions="+collector.actions);
+ System.out.println("scopes="+collector.scopes);
+ */
+ }
+
+ public void process() {
+ // methods affect fields, but no side-effects outside this object
+ // So, call order sensitive
+ // First collect all rules for later use in checkForLabelConflict()
+ if ( g.rules!=null ) {
+ for (Rule r : g.rules.values()) nameToRuleMap.put(r.name, r);
+ }
+ checkReservedNames(g.rules.values());
+ checkActionRedefinitions(collector.namedActions);
+ checkForTokenConflicts(collector.tokenIDRefs); // sets tokenIDs
+ checkForLabelConflicts(g.rules.values());
+ }
+
+ public void checkActionRedefinitions(List<GrammarAST> actions) {
+ if ( actions==null ) return;
+ String scope = g.getDefaultActionScope();
+ String name;
+ GrammarAST nameNode;
+ for (GrammarAST ampersandAST : actions) {
+ nameNode = (GrammarAST)ampersandAST.getChild(0);
+ if ( ampersandAST.getChildCount()==2 ) {
+ name = nameNode.getText();
+ }
+ else {
+ scope = nameNode.getText();
+ name = ampersandAST.getChild(1).getText();
+ }
+ Set<String> scopeActions = actionScopeToActionNames.get(scope);
+ if ( scopeActions==null ) { // init scope
+ scopeActions = new HashSet<String>();
+ actionScopeToActionNames.put(scope, scopeActions);
+ }
+ if ( !scopeActions.contains(name) ) {
+ scopeActions.add(name);
+ }
+ else {
+ errMgr.grammarError(ErrorType.ACTION_REDEFINITION,
+ g.fileName, nameNode.token, name);
+ }
+ }
+ }
+
+ public void checkForTokenConflicts(List<GrammarAST> tokenIDRefs) {
+// for (GrammarAST a : tokenIDRefs) {
+// Token t = a.token;
+// String ID = t.getText();
+// tokenIDs.add(ID);
+// }
+ }
+
+ /** Make sure a label doesn't conflict with another symbol.
+ * Labels must not conflict with: rules, tokens, scope names,
+ * return values, parameters, and rule-scope dynamic attributes
+ * defined in surrounding rule. Also they must have same type
+ * for repeated defs.
+ */
+ public void checkForLabelConflicts(Collection<Rule> rules) {
+ for (Rule r : rules) {
+ checkForAttributeConflicts(r);
+ Map<String, LabelElementPair> labelNameSpace =
+ new HashMap<String, LabelElementPair>();
+ for (int i=1; i<=r.numberOfAlts; i++) {
+ if (r.hasAltSpecificContexts()) {
+ labelNameSpace.clear();
+ }
+
+ Alternative a = r.alt[i];
+ for (List<LabelElementPair> pairs : a.labelDefs.values() ) {
+ for (LabelElementPair p : pairs) {
+ checkForLabelConflict(r, p.label);
+ String name = p.label.getText();
+ LabelElementPair prev = labelNameSpace.get(name);
+ if ( prev==null ) labelNameSpace.put(name, p);
+ else checkForTypeMismatch(prev, p);
+ }
+ }
+ }
+ }
+ }
+
+ void checkForTypeMismatch(LabelElementPair prevLabelPair,
+ LabelElementPair labelPair)
+ {
+ // label already defined; if same type, no problem
+ if ( prevLabelPair.type != labelPair.type ) {
+ String typeMismatchExpr = labelPair.type+"!="+prevLabelPair.type;
+ errMgr.grammarError(
+ ErrorType.LABEL_TYPE_CONFLICT,
+ g.fileName,
+ labelPair.label.token,
+ labelPair.label.getText(),
+ typeMismatchExpr);
+ }
+ }
+
+ public void checkForLabelConflict(Rule r, GrammarAST labelID) {
+ String name = labelID.getText();
+ if (nameToRuleMap.containsKey(name)) {
+ ErrorType etype = ErrorType.LABEL_CONFLICTS_WITH_RULE;
+ errMgr.grammarError(etype, g.fileName, labelID.token, name, r.name);
+ }
+
+ if (tokenIDs.contains(name)) {
+ ErrorType etype = ErrorType.LABEL_CONFLICTS_WITH_TOKEN;
+ errMgr.grammarError(etype, g.fileName, labelID.token, name, r.name);
+ }
+
+ if (r.args != null && r.args.get(name) != null) {
+ ErrorType etype = ErrorType.LABEL_CONFLICTS_WITH_ARG;
+ errMgr.grammarError(etype, g.fileName, labelID.token, name, r.name);
+ }
+
+ if (r.retvals != null && r.retvals.get(name) != null) {
+ ErrorType etype = ErrorType.LABEL_CONFLICTS_WITH_RETVAL;
+ errMgr.grammarError(etype, g.fileName, labelID.token, name, r.name);
+ }
+
+ if (r.locals != null && r.locals.get(name) != null) {
+ ErrorType etype = ErrorType.LABEL_CONFLICTS_WITH_LOCAL;
+ errMgr.grammarError(etype, g.fileName, labelID.token, name, r.name);
+ }
+ }
+
+ public void checkForAttributeConflicts(Rule r) {
+ checkDeclarationRuleConflicts(r, r.args, nameToRuleMap.keySet(), ErrorType.ARG_CONFLICTS_WITH_RULE);
+ checkDeclarationRuleConflicts(r, r.args, tokenIDs, ErrorType.ARG_CONFLICTS_WITH_TOKEN);
+
+ checkDeclarationRuleConflicts(r, r.retvals, nameToRuleMap.keySet(), ErrorType.RETVAL_CONFLICTS_WITH_RULE);
+ checkDeclarationRuleConflicts(r, r.retvals, tokenIDs, ErrorType.RETVAL_CONFLICTS_WITH_TOKEN);
+
+ checkDeclarationRuleConflicts(r, r.locals, nameToRuleMap.keySet(), ErrorType.LOCAL_CONFLICTS_WITH_RULE);
+ checkDeclarationRuleConflicts(r, r.locals, tokenIDs, ErrorType.LOCAL_CONFLICTS_WITH_TOKEN);
+
+ checkLocalConflictingDeclarations(r, r.retvals, r.args, ErrorType.RETVAL_CONFLICTS_WITH_ARG);
+ checkLocalConflictingDeclarations(r, r.locals, r.args, ErrorType.LOCAL_CONFLICTS_WITH_ARG);
+ checkLocalConflictingDeclarations(r, r.locals, r.retvals, ErrorType.LOCAL_CONFLICTS_WITH_RETVAL);
+ }
+
+ protected void checkDeclarationRuleConflicts(Rule r, AttributeDict attributes, Set<String> ruleNames, ErrorType errorType) {
+ if (attributes == null) {
+ return;
+ }
+
+ for (Attribute attribute : attributes.attributes.values()) {
+ if (ruleNames.contains(attribute.name)) {
+ errMgr.grammarError(
+ errorType,
+ g.fileName,
+ attribute.token != null ? attribute.token : ((GrammarAST)r.ast.getChild(0)).token,
+ attribute.name,
+ r.name);
+ }
+ }
+ }
+
+ protected void checkLocalConflictingDeclarations(Rule r, AttributeDict attributes, AttributeDict referenceAttributes, ErrorType errorType) {
+ if (attributes == null || referenceAttributes == null) {
+ return;
+ }
+
+ Set<String> conflictingKeys = attributes.intersection(referenceAttributes);
+ for (String key : conflictingKeys) {
+ errMgr.grammarError(
+ errorType,
+ g.fileName,
+ attributes.get(key).token != null ? attributes.get(key).token : ((GrammarAST) r.ast.getChild(0)).token,
+ key,
+ r.name);
+ }
+ }
+
+ protected void checkReservedNames(Collection<Rule> rules) {
+ for (Rule rule : rules) {
+ if (reservedNames.contains(rule.name)) {
+ errMgr.grammarError(ErrorType.RESERVED_RULE_NAME, g.fileName, ((GrammarAST)rule.ast.getChild(0)).getToken(), rule.name);
+ }
+ }
+ }
+
+ // CAN ONLY CALL THE TWO NEXT METHODS AFTER GRAMMAR HAS RULE DEFS (see semanticpipeline)
+
+ public void checkRuleArgs(Grammar g, List<GrammarAST> rulerefs) {
+ if ( rulerefs==null ) return;
+ for (GrammarAST ref : rulerefs) {
+ String ruleName = ref.getText();
+ Rule r = g.getRule(ruleName);
+ GrammarAST arg = (GrammarAST)ref.getFirstChildWithType(ANTLRParser.ARG_ACTION);
+ if ( arg!=null && (r==null || r.args==null) ) {
+ errMgr.grammarError(ErrorType.RULE_HAS_NO_ARGS,
+ g.fileName, ref.token, ruleName);
+
+ }
+ else if ( arg==null && (r!=null&&r.args!=null) ) {
+ errMgr.grammarError(ErrorType.MISSING_RULE_ARGS,
+ g.fileName, ref.token, ruleName);
+ }
+ }
+ }
+
+ public void checkForQualifiedRuleIssues(Grammar g, List<GrammarAST> qualifiedRuleRefs) {
+ for (GrammarAST dot : qualifiedRuleRefs) {
+ GrammarAST grammar = (GrammarAST)dot.getChild(0);
+ GrammarAST rule = (GrammarAST)dot.getChild(1);
+ g.tool.log("semantics", grammar.getText()+"."+rule.getText());
+ Grammar delegate = g.getImportedGrammar(grammar.getText());
+ if ( delegate==null ) {
+ errMgr.grammarError(ErrorType.NO_SUCH_GRAMMAR_SCOPE,
+ g.fileName, grammar.token, grammar.getText(),
+ rule.getText());
+ }
+ else {
+ if ( g.getRule(grammar.getText(), rule.getText())==null ) {
+ errMgr.grammarError(ErrorType.NO_SUCH_RULE_IN_SCOPE,
+ g.fileName, rule.token, grammar.getText(),
+ rule.getText());
+ }
+ }
+ }
+ }
+}
diff --git a/tool/src/org/antlr/v4/semantics/SymbolCollector.java b/tool/src/org/antlr/v4/semantics/SymbolCollector.java
new file mode 100644
index 0000000..b0c43a4
--- /dev/null
+++ b/tool/src/org/antlr/v4/semantics/SymbolCollector.java
@@ -0,0 +1,213 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.semantics;
+
+import org.antlr.v4.parse.GrammarTreeVisitor;
+import org.antlr.v4.tool.ErrorManager;
+import org.antlr.v4.tool.Grammar;
+import org.antlr.v4.tool.LabelElementPair;
+import org.antlr.v4.tool.Rule;
+import org.antlr.v4.tool.ast.ActionAST;
+import org.antlr.v4.tool.ast.AltAST;
+import org.antlr.v4.tool.ast.GrammarAST;
+import org.antlr.v4.tool.ast.GrammarASTWithOptions;
+import org.antlr.v4.tool.ast.PredAST;
+import org.antlr.v4.tool.ast.RuleAST;
+import org.antlr.v4.tool.ast.TerminalAST;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/** Collects (create) rules, terminals, strings, actions, scopes etc... from AST
+ * side-effects: sets resolver field of asts for actions and
+ * defines predicates via definePredicateInAlt(), collects actions and stores
+ * in alts.
+ * TODO: remove side-effects!
+ */
+public class SymbolCollector extends GrammarTreeVisitor {
+ /** which grammar are we checking */
+ public Grammar g;
+
+ // stuff to collect
+ public List<GrammarAST> rulerefs = new ArrayList<GrammarAST>();
+ public List<GrammarAST> qualifiedRulerefs = new ArrayList<GrammarAST>();
+ public List<GrammarAST> terminals = new ArrayList<GrammarAST>();
+ public List<GrammarAST> tokenIDRefs = new ArrayList<GrammarAST>();
+ public Set<String> strings = new HashSet<String>();
+ public List<GrammarAST> tokensDefs = new ArrayList<GrammarAST>();
+ public List<GrammarAST> channelDefs = new ArrayList<GrammarAST>();
+
+ /** Track action name node in @parser::members {...} or @members {...} */
+ List<GrammarAST> namedActions = new ArrayList<GrammarAST>();
+
+ public ErrorManager errMgr;
+
+ // context
+ public Rule currentRule;
+
+ public SymbolCollector(Grammar g) {
+ this.g = g;
+ this.errMgr = g.tool.errMgr;
+ }
+
+ @Override
+ public ErrorManager getErrorManager() { return errMgr; }
+
+ public void process(GrammarAST ast) { visitGrammar(ast); }
+
+ @Override
+ public void globalNamedAction(GrammarAST scope, GrammarAST ID, ActionAST action) {
+ namedActions.add((GrammarAST)ID.getParent());
+ action.resolver = g;
+ }
+
+ @Override
+ public void defineToken(GrammarAST ID) {
+ terminals.add(ID);
+ tokenIDRefs.add(ID);
+ tokensDefs.add(ID);
+ }
+
+ @Override
+ public void defineChannel(GrammarAST ID) {
+ channelDefs.add(ID);
+ }
+
+ @Override
+ public void discoverRule(RuleAST rule, GrammarAST ID,
+ List<GrammarAST> modifiers, ActionAST arg,
+ ActionAST returns, GrammarAST thrws,
+ GrammarAST options, ActionAST locals,
+ List<GrammarAST> actions,
+ GrammarAST block)
+ {
+ currentRule = g.getRule(ID.getText());
+ }
+
+ @Override
+ public void discoverLexerRule(RuleAST rule, GrammarAST ID, List<GrammarAST> modifiers,
+ GrammarAST block)
+ {
+ currentRule = g.getRule(ID.getText());
+ }
+
+ @Override
+ public void discoverOuterAlt(AltAST alt) {
+ currentRule.alt[currentOuterAltNumber].ast = alt;
+ }
+
+ @Override
+ public void actionInAlt(ActionAST action) {
+ currentRule.defineActionInAlt(currentOuterAltNumber, action);
+ action.resolver = currentRule.alt[currentOuterAltNumber];
+ }
+
+ @Override
+ public void sempredInAlt(PredAST pred) {
+ currentRule.definePredicateInAlt(currentOuterAltNumber, pred);
+ pred.resolver = currentRule.alt[currentOuterAltNumber];
+ }
+
+ @Override
+ public void ruleCatch(GrammarAST arg, ActionAST action) {
+ GrammarAST catchme = (GrammarAST)action.getParent();
+ currentRule.exceptions.add(catchme);
+ action.resolver = currentRule;
+ }
+
+ @Override
+ public void finallyAction(ActionAST action) {
+ currentRule.finallyAction = action;
+ action.resolver = currentRule;
+ }
+
+ @Override
+ public void label(GrammarAST op, GrammarAST ID, GrammarAST element) {
+ LabelElementPair lp = new LabelElementPair(g, ID, element, op.getType());
+ currentRule.alt[currentOuterAltNumber].labelDefs.map(ID.getText(), lp);
+ }
+
+ @Override
+ public void stringRef(TerminalAST ref) {
+ terminals.add(ref);
+ strings.add(ref.getText());
+ if ( currentRule!=null ) {
+ currentRule.alt[currentOuterAltNumber].tokenRefs.map(ref.getText(), ref);
+ }
+ }
+
+ @Override
+ public void tokenRef(TerminalAST ref) {
+ terminals.add(ref);
+ tokenIDRefs.add(ref);
+ if ( currentRule!=null ) {
+ currentRule.alt[currentOuterAltNumber].tokenRefs.map(ref.getText(), ref);
+ }
+ }
+
+ @Override
+ public void ruleRef(GrammarAST ref, ActionAST arg) {
+// if ( inContext("DOT ...") ) qualifiedRulerefs.add((GrammarAST)ref.getParent());
+ rulerefs.add(ref);
+ if ( currentRule!=null ) {
+ currentRule.alt[currentOuterAltNumber].ruleRefs.map(ref.getText(), ref);
+ }
+ }
+
+ @Override
+ public void grammarOption(GrammarAST ID, GrammarAST valueAST) {
+ setActionResolver(valueAST);
+ }
+
+ @Override
+ public void ruleOption(GrammarAST ID, GrammarAST valueAST) {
+ setActionResolver(valueAST);
+ }
+
+ @Override
+ public void blockOption(GrammarAST ID, GrammarAST valueAST) {
+ setActionResolver(valueAST);
+ }
+
+ @Override
+ public void elementOption(GrammarASTWithOptions t, GrammarAST ID, GrammarAST valueAST) {
+ setActionResolver(valueAST);
+ }
+
+ /** In case of option id={...}, set resolve in case they use $foo */
+ private void setActionResolver(GrammarAST valueAST) {
+ if ( valueAST instanceof ActionAST) {
+ ((ActionAST)valueAST).resolver = currentRule.alt[currentOuterAltNumber];
+ }
+ }
+}
diff --git a/tool/src/org/antlr/v4/semantics/UseDefAnalyzer.java b/tool/src/org/antlr/v4/semantics/UseDefAnalyzer.java
new file mode 100644
index 0000000..ac788e1
--- /dev/null
+++ b/tool/src/org/antlr/v4/semantics/UseDefAnalyzer.java
@@ -0,0 +1,119 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.semantics;
+
+import org.antlr.runtime.ANTLRStringStream;
+import org.antlr.runtime.Token;
+import org.antlr.v4.parse.ANTLRParser;
+import org.antlr.v4.parse.ActionSplitter;
+import org.antlr.v4.parse.ActionSplitterListener;
+import org.antlr.v4.tool.Alternative;
+import org.antlr.v4.tool.Grammar;
+import org.antlr.v4.tool.LexerGrammar;
+import org.antlr.v4.tool.Rule;
+import org.antlr.v4.tool.ast.ActionAST;
+import org.antlr.v4.tool.ast.GrammarAST;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/** Look for errors and deadcode stuff */
+public class UseDefAnalyzer {
+ // side-effect: updates Alternative with refs in actions
+ public static void trackTokenRuleRefsInActions(Grammar g) {
+ for (Rule r : g.rules.values()) {
+ for (int i=1; i<=r.numberOfAlts; i++) {
+ Alternative alt = r.alt[i];
+ for (ActionAST a : alt.actions) {
+ ActionSniffer sniffer = new ActionSniffer(g, r, alt, a, a.token);
+ sniffer.examineAction();
+ }
+ }
+ }
+ }
+
+ public static boolean actionIsContextDependent(ActionAST actionAST) {
+ ANTLRStringStream in = new ANTLRStringStream(actionAST.token.getText());
+ in.setLine(actionAST.token.getLine());
+ in.setCharPositionInLine(actionAST.token.getCharPositionInLine());
+ final boolean[] dependent = new boolean[] {false}; // can't be simple bool with anon class
+ ActionSplitterListener listener = new BlankActionSplitterListener() {
+ @Override
+ public void nonLocalAttr(String expr, Token x, Token y) { dependent[0] = true; }
+ @Override
+ public void qualifiedAttr(String expr, Token x, Token y) { dependent[0] = true; }
+ @Override
+ public void setAttr(String expr, Token x, Token rhs) { dependent[0] = true; }
+ @Override
+ public void setExprAttribute(String expr) { dependent[0] = true; }
+ @Override
+ public void setNonLocalAttr(String expr, Token x, Token y, Token rhs) { dependent[0] = true; }
+ @Override
+ public void attr(String expr, Token x) { dependent[0] = true; }
+ };
+ ActionSplitter splitter = new ActionSplitter(in, listener);
+ // forces eval, triggers listener methods
+ splitter.getActionTokens();
+ return dependent[0];
+ }
+
+ /** Find all rules reachable from r directly or indirectly for all r in g */
+ public static Map<Rule, Set<Rule>> getRuleDependencies(Grammar g) {
+ return getRuleDependencies(g, g.rules.values());
+ }
+
+ public static Map<Rule, Set<Rule>> getRuleDependencies(LexerGrammar g, String modeName) {
+ return getRuleDependencies(g, g.modes.get(modeName));
+ }
+
+ public static Map<Rule, Set<Rule>> getRuleDependencies(Grammar g, Collection<Rule> rules) {
+ Map<Rule, Set<Rule>> dependencies = new HashMap<Rule, Set<Rule>>();
+
+ for (Rule r : rules) {
+ List<GrammarAST> tokenRefs = r.ast.getNodesWithType(ANTLRParser.TOKEN_REF);
+ for (GrammarAST tref : tokenRefs) {
+ Set<Rule> calls = dependencies.get(r);
+ if ( calls==null ) {
+ calls = new HashSet<Rule>();
+ dependencies.put(r, calls);
+ }
+ calls.add(g.getRule(tref.getText()));
+ }
+ }
+
+ return dependencies;
+ }
+
+}
diff --git a/tool/src/org/antlr/v4/tool/ANTLRMessage.java b/tool/src/org/antlr/v4/tool/ANTLRMessage.java
new file mode 100644
index 0000000..36d9ab9
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/ANTLRMessage.java
@@ -0,0 +1,130 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.tool;
+
+import org.antlr.runtime.Token;
+import org.stringtemplate.v4.ST;
+
+import java.util.Arrays;
+
+public class ANTLRMessage {
+ private static final Object[] EMPTY_ARGS = new Object[0];
+
+
+ private final ErrorType errorType;
+
+ private final Object[] args;
+
+ private final Throwable e;
+
+ // used for location template
+ public String fileName;
+ public int line = -1;
+ public int charPosition = -1;
+
+ public Grammar g;
+ /** Most of the time, we'll have a token such as an undefined rule ref
+ * and so this will be set.
+ */
+ public Token offendingToken;
+
+ public ANTLRMessage(ErrorType errorType) {
+ this(errorType, (Throwable)null, Token.INVALID_TOKEN);
+ }
+
+ public ANTLRMessage(ErrorType errorType, Token offendingToken, Object... args) {
+ this(errorType, null, offendingToken, args);
+ }
+
+ public ANTLRMessage(ErrorType errorType, Throwable e, Token offendingToken, Object... args) {
+ this.errorType = errorType;
+ this.e = e;
+ this.args = args;
+ this.offendingToken = offendingToken;
+ }
+
+
+ public ErrorType getErrorType() {
+ return errorType;
+ }
+
+
+ public Object[] getArgs() {
+ if (args == null) {
+ return EMPTY_ARGS;
+ }
+
+ return args;
+ }
+
+ public ST getMessageTemplate(boolean verbose) {
+ ST messageST = new ST(getErrorType().msg);
+ messageST.impl.name = errorType.name();
+
+ messageST.add("verbose", verbose);
+ Object[] args = getArgs();
+ for (int i=0; i<args.length; i++) {
+ String attr = "arg";
+ if ( i>0 ) attr += i + 1;
+ messageST.add(attr, args[i]);
+ }
+ if ( args.length<2 ) messageST.add("arg2", null); // some messages ref arg2
+
+ Throwable cause = getCause();
+ if ( cause!=null ) {
+ messageST.add("exception", cause);
+ messageST.add("stackTrace", cause.getStackTrace());
+ }
+ else {
+ messageST.add("exception", null); // avoid ST error msg
+ messageST.add("stackTrace", null);
+ }
+
+ return messageST;
+ }
+
+
+ public Throwable getCause() {
+ return e;
+ }
+
+ @Override
+ public String toString() {
+ return "Message{" +
+ "errorType=" + getErrorType() +
+ ", args=" + Arrays.asList(getArgs()) +
+ ", e=" + getCause() +
+ ", fileName='" + fileName + '\'' +
+ ", line=" + line +
+ ", charPosition=" + charPosition +
+ '}';
+ }
+}
diff --git a/tool/src/org/antlr/v4/tool/ANTLRToolListener.java b/tool/src/org/antlr/v4/tool/ANTLRToolListener.java
new file mode 100644
index 0000000..76a73a0
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/ANTLRToolListener.java
@@ -0,0 +1,44 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.tool;
+
+/** Defines behavior of object able to handle error messages from ANTLR including
+ * both tool errors like "can't write file" and grammar ambiguity warnings.
+ * To avoid having to change tools that use ANTLR (like GUIs), I am
+ * wrapping error data in Message objects and passing them to the listener.
+ * In this way, users of this interface are less sensitive to changes in
+ * the info I need for error messages.
+ */
+public interface ANTLRToolListener {
+ public void info(String msg);
+ public void error(ANTLRMessage msg);
+ public void warning(ANTLRMessage msg);
+}
diff --git a/tool/src/org/antlr/v4/tool/Alternative.java b/tool/src/org/antlr/v4/tool/Alternative.java
new file mode 100644
index 0000000..3d5e1cb
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/Alternative.java
@@ -0,0 +1,163 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.tool;
+
+
+import org.antlr.v4.tool.ast.ActionAST;
+import org.antlr.v4.tool.ast.AltAST;
+import org.antlr.v4.tool.ast.GrammarAST;
+import org.antlr.v4.tool.ast.TerminalAST;
+import org.stringtemplate.v4.misc.MultiMap;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** An outermost alternative for a rule. We don't track inner alternatives. */
+public class Alternative implements AttributeResolver {
+ public Rule rule;
+
+ public AltAST ast;
+
+ /** What alternative number is this outermost alt? 1..n */
+ public int altNum;
+
+ // token IDs, string literals in this alt
+ public MultiMap<String, TerminalAST> tokenRefs = new MultiMap<String, TerminalAST>();
+
+ // does not include labels
+ public MultiMap<String, GrammarAST> tokenRefsInActions = new MultiMap<String, GrammarAST>();
+
+ // all rule refs in this alt
+ public MultiMap<String, GrammarAST> ruleRefs = new MultiMap<String, GrammarAST>();
+
+ // does not include labels
+ public MultiMap<String, GrammarAST> ruleRefsInActions = new MultiMap<String, GrammarAST>();
+
+ /** A list of all LabelElementPair attached to tokens like id=ID, ids+=ID */
+ public MultiMap<String, LabelElementPair> labelDefs = new MultiMap<String, LabelElementPair>();
+
+ // track all token, rule, label refs in rewrite (right of ->)
+ //public List<GrammarAST> rewriteElements = new ArrayList<GrammarAST>();
+
+ /** Track all executable actions other than named actions like @init
+ * and catch/finally (not in an alt). Also tracks predicates, rewrite actions.
+ * We need to examine these actions before code generation so
+ * that we can detect refs to $rule.attr etc...
+ *
+ * This tracks per alt
+ */
+ public List<ActionAST> actions = new ArrayList<ActionAST>();
+
+ public Alternative(Rule r, int altNum) { this.rule = r; this.altNum = altNum; }
+
+ @Override
+ public boolean resolvesToToken(String x, ActionAST node) {
+ if ( tokenRefs.get(x)!=null ) return true;
+ LabelElementPair anyLabelDef = getAnyLabelDef(x);
+ if ( anyLabelDef!=null && anyLabelDef.type==LabelType.TOKEN_LABEL ) return true;
+ return false;
+ }
+
+ @Override
+ public boolean resolvesToAttributeDict(String x, ActionAST node) {
+ if ( resolvesToToken(x, node) ) return true;
+ if ( ruleRefs.get(x)!=null ) return true; // rule ref in this alt?
+ LabelElementPair anyLabelDef = getAnyLabelDef(x);
+ if ( anyLabelDef!=null && anyLabelDef.type==LabelType.RULE_LABEL ) return true;
+ return false;
+ }
+
+ /** $x Attribute: rule arguments, return values, predefined rule prop.
+ */
+ @Override
+ public Attribute resolveToAttribute(String x, ActionAST node) {
+ return rule.resolveToAttribute(x, node); // reuse that code
+ }
+
+ /** $x.y, x can be surrounding rule, token/rule/label ref. y is visible
+ * attr in that dictionary. Can't see args on rule refs.
+ */
+ @Override
+ public Attribute resolveToAttribute(String x, String y, ActionAST node) {
+ if ( tokenRefs.get(x)!=null ) { // token ref in this alt?
+ return rule.getPredefinedScope(LabelType.TOKEN_LABEL).get(y);
+ }
+ if ( ruleRefs.get(x)!=null ) { // rule ref in this alt?
+ // look up rule, ask it to resolve y (must be retval or predefined)
+ return rule.g.getRule(x).resolveRetvalOrProperty(y);
+ }
+ LabelElementPair anyLabelDef = getAnyLabelDef(x);
+ if ( anyLabelDef!=null && anyLabelDef.type==LabelType.RULE_LABEL ) {
+ return rule.g.getRule(anyLabelDef.element.getText()).resolveRetvalOrProperty(y);
+ }
+ else if ( anyLabelDef!=null ) {
+ AttributeDict scope = rule.getPredefinedScope(anyLabelDef.type);
+ if (scope == null) {
+ return null;
+ }
+
+ return scope.get(y);
+ }
+ return null;
+ }
+
+ @Override
+ public boolean resolvesToLabel(String x, ActionAST node) {
+ LabelElementPair anyLabelDef = getAnyLabelDef(x);
+ return anyLabelDef!=null &&
+ (anyLabelDef.type==LabelType.TOKEN_LABEL ||
+ anyLabelDef.type==LabelType.RULE_LABEL);
+ }
+
+ @Override
+ public boolean resolvesToListLabel(String x, ActionAST node) {
+ LabelElementPair anyLabelDef = getAnyLabelDef(x);
+ return anyLabelDef!=null &&
+ (anyLabelDef.type==LabelType.RULE_LIST_LABEL ||
+ anyLabelDef.type==LabelType.TOKEN_LIST_LABEL);
+ }
+
+ public LabelElementPair getAnyLabelDef(String x) {
+ List<LabelElementPair> labels = labelDefs.get(x);
+ if ( labels!=null ) return labels.get(0);
+ return null;
+ }
+
+ /** x can be ruleref or rule label. */
+ public Rule resolveToRule(String x) {
+ if ( ruleRefs.get(x)!=null ) return rule.g.getRule(x);
+ LabelElementPair anyLabelDef = getAnyLabelDef(x);
+ if ( anyLabelDef!=null && anyLabelDef.type==LabelType.RULE_LABEL ) {
+ return rule.g.getRule(anyLabelDef.element.getText());
+ }
+ return null;
+ }
+}
diff --git a/tool/src/org/antlr/v4/tool/Attribute.java b/tool/src/org/antlr/v4/tool/Attribute.java
new file mode 100644
index 0000000..3dc0258
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/Attribute.java
@@ -0,0 +1,73 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.tool;
+
+import org.antlr.runtime.Token;
+
+/** Track the names of attributes define in arg lists, return values,
+ * scope blocks etc...
+ */
+public class Attribute {
+ /** The entire declaration such as "String foo;" */
+ public String decl;
+
+ /** The type; might be empty such as for Python which has no static typing */
+ public String type;
+
+ /** The name of the attribute "foo" */
+ public String name;
+
+ /** A {@link Token} giving the position of the name of this attribute in the grammar. */
+ public Token token;
+
+ /** The optional attribute initialization expression */
+ public String initValue;
+
+ /** Who contains us? */
+ public AttributeDict dict;
+
+ public Attribute() {}
+
+ public Attribute(String name) { this(name,null); }
+
+ public Attribute(String name, String decl) {
+ this.name = name;
+ this.decl = decl;
+ }
+
+ @Override
+ public String toString() {
+ if ( initValue!=null ) {
+ return type+" "+name+"="+initValue;
+ }
+ return type+" "+name;
+ }
+} \ No newline at end of file
diff --git a/tool/src/org/antlr/v4/tool/AttributeDict.java b/tool/src/org/antlr/v4/tool/AttributeDict.java
new file mode 100644
index 0000000..911170d
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/AttributeDict.java
@@ -0,0 +1,108 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.tool;
+
+import org.antlr.v4.runtime.Token;
+import org.antlr.v4.tool.ast.GrammarAST;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.Set;
+
+/** Track the attributes within retval, arg lists etc...
+ * <p/>
+ * Each rule has potentially 3 scopes: return values,
+ * parameters, and an implicitly-named scope (i.e., a scope defined in a rule).
+ * Implicitly-defined scopes are named after the rule; rules and scopes then
+ * must live in the same name space--no collisions allowed.
+ */
+public class AttributeDict {
+ public String name;
+ public GrammarAST ast;
+ public DictType type;
+
+ /** All {@link Token} scopes (token labels) share the same fixed scope of
+ * of predefined attributes. I keep this out of the {@link Token}
+ * interface to avoid a runtime type leakage.
+ */
+ public static final AttributeDict predefinedTokenDict = new AttributeDict(DictType.TOKEN);
+ static {
+ predefinedTokenDict.add(new Attribute("text"));
+ predefinedTokenDict.add(new Attribute("type"));
+ predefinedTokenDict.add(new Attribute("line"));
+ predefinedTokenDict.add(new Attribute("index"));
+ predefinedTokenDict.add(new Attribute("pos"));
+ predefinedTokenDict.add(new Attribute("channel"));
+ predefinedTokenDict.add(new Attribute("int"));
+ }
+
+ public static enum DictType {
+ ARG, RET, LOCAL, TOKEN,
+ PREDEFINED_RULE, PREDEFINED_LEXER_RULE,
+ }
+
+ /** The list of {@link Attribute} objects. */
+
+ public final LinkedHashMap<String, Attribute> attributes =
+ new LinkedHashMap<String, Attribute>();
+
+ public AttributeDict() {}
+ public AttributeDict(DictType type) { this.type = type; }
+
+ public Attribute add(Attribute a) { a.dict = this; return attributes.put(a.name, a); }
+ public Attribute get(String name) { return attributes.get(name); }
+
+ public String getName() {
+ return name;
+ }
+
+ public int size() { return attributes.size(); }
+
+ /** Return the set of keys that collide from
+ * {@code this} and {@code other}.
+ */
+
+ public Set<String> intersection(AttributeDict other) {
+ if ( other==null || other.size()==0 || size()==0 ) {
+ return Collections.emptySet();
+ }
+
+ Set<String> result = new HashSet<String>(attributes.keySet());
+ result.retainAll(other.attributes.keySet());
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return getName()+":"+attributes;
+ }
+}
diff --git a/tool/src/org/antlr/v4/tool/AttributeResolver.java b/tool/src/org/antlr/v4/tool/AttributeResolver.java
new file mode 100644
index 0000000..ee01ee1
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/AttributeResolver.java
@@ -0,0 +1,71 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.tool;
+
+import org.antlr.v4.tool.ast.ActionAST;
+
+/** Grammars, rules, and alternatives all have symbols visible to
+ * actions. To evaluate attr exprs, ask action for its resolver
+ * then ask resolver to look up various symbols. Depending on the context,
+ * some symbols are available at some aren't.
+ *
+ * Alternative level:
+ *
+ * $x Attribute: rule arguments, return values, predefined rule prop.
+ * AttributeDict: references to tokens and token labels in the
+ * current alt (including any elements within subrules contained
+ * in that outermost alt). x can be rule with scope or a global scope.
+ * List label: x is a token/rule list label.
+ * $x.y Attribute: x is surrounding rule, rule/token/label ref
+ * $s::y Attribute: s is any rule with scope or global scope; y is prop within
+ *
+ * Rule level:
+ *
+ * $x Attribute: rule arguments, return values, predefined rule prop.
+ * AttributeDict: references to token labels in *any* alt. x can
+ * be any rule with scope or global scope.
+ * List label: x is a token/rule list label.
+ * $x.y Attribute: x is surrounding rule, label ref (in any alts)
+ * $s::y Attribute: s is any rule with scope or global scope; y is prop within
+ *
+ * Grammar level:
+ *
+ * $s AttributeDict: s is a global scope
+ * $s::y Attribute: s is a global scope; y is prop within
+ */
+public interface AttributeResolver {
+ public boolean resolvesToListLabel(String x, ActionAST node);
+ public boolean resolvesToLabel(String x, ActionAST node);
+ public boolean resolvesToAttributeDict(String x, ActionAST node);
+ public boolean resolvesToToken(String x, ActionAST node);
+ public Attribute resolveToAttribute(String x, ActionAST node);
+ public Attribute resolveToAttribute(String x, String y, ActionAST node);
+}
diff --git a/tool/src/org/antlr/v4/tool/BuildDependencyGenerator.java b/tool/src/org/antlr/v4/tool/BuildDependencyGenerator.java
new file mode 100644
index 0000000..69e71b5
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/BuildDependencyGenerator.java
@@ -0,0 +1,273 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.v4.tool;
+
+import org.antlr.v4.Tool;
+import org.antlr.v4.codegen.CodeGenerator;
+import org.antlr.v4.parse.ANTLRParser;
+import org.stringtemplate.v4.ST;
+import org.stringtemplate.v4.STGroup;
+import org.stringtemplate.v4.STGroupFile;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+/** Given a grammar file, show the dependencies on .tokens etc...
+ * Using ST, emit a simple "make compatible" list of dependencies.
+ * For example, combined grammar T.g (no token import) generates:
+ *
+ * TParser.java : T.g
+ * T.tokens : T.g
+ * TLexer.java : T.g
+ *
+ * If we are using the listener pattern (-listener on the command line)
+ * then we add:
+ *
+ * TListener.java : T.g
+ * TBaseListener.java : T.g
+ *
+ * If we are using the visitor pattern (-visitor on the command line)
+ * then we add:
+ *
+ * TVisitor.java : T.g
+ * TBaseVisitor.java : T.g
+ *
+ * If "-lib libdir" is used on command-line with -depend and option
+ * tokenVocab=A in grammar, then include the path like this:
+ *
+ * T.g: libdir/A.tokens
+ *
+ * Pay attention to -o as well:
+ *
+ * outputdir/TParser.java : T.g
+ *
+ * So this output shows what the grammar depends on *and* what it generates.
+ *
+ * Operate on one grammar file at a time. If given a list of .g on the
+ * command-line with -depend, just emit the dependencies. The grammars
+ * may depend on each other, but the order doesn't matter. Build tools,
+ * reading in this output, will know how to organize it.
+ *
+ * This code was obvious until I removed redundant "./" on front of files
+ * and had to escape spaces in filenames :(
+ *
+ * I literally copied from v3 so might be slightly inconsistent with the
+ * v4 code base.
+ */
+public class BuildDependencyGenerator {
+ protected Tool tool;
+ protected Grammar g;
+ protected CodeGenerator generator;
+ protected STGroup templates;
+
+ public BuildDependencyGenerator(Tool tool, Grammar g) {
+ this.tool = tool;
+ this.g = g;
+ String language = g.getOptionString("language");
+ generator = new CodeGenerator(tool, g, language);
+ }
+
+ /** From T.g return a list of File objects that
+ * name files ANTLR will emit from T.g.
+ */
+ public List<File> getGeneratedFileList() {
+ List<File> files = new ArrayList<File>();
+
+ // add generated recognizer; e.g., TParser.java
+ files.add(getOutputFile(generator.getRecognizerFileName()));
+ // add output vocab file; e.g., T.tokens. This is always generated to
+ // the base output directory, which will be just . if there is no -o option
+ //
+ files.add(getOutputFile(generator.getVocabFileName()));
+ // are we generating a .h file?
+ ST headerExtST = null;
+ ST extST = generator.getTemplates().getInstanceOf("codeFileExtension");
+ if (generator.getTemplates().isDefined("headerFile")) {
+ headerExtST = generator.getTemplates().getInstanceOf("headerFileExtension");
+ String suffix = Grammar.getGrammarTypeToFileNameSuffix(g.getType());
+ String fileName = g.name + suffix + headerExtST.render();
+ files.add(getOutputFile(fileName));
+ }
+ if ( g.isCombined() ) {
+ // add autogenerated lexer; e.g., TLexer.java TLexer.h TLexer.tokens
+
+ String suffix = Grammar.getGrammarTypeToFileNameSuffix(ANTLRParser.LEXER);
+ String lexer = g.name + suffix + extST.render();
+ files.add(getOutputFile(lexer));
+ String lexerTokens = g.name + suffix + CodeGenerator.VOCAB_FILE_EXTENSION;
+ files.add(getOutputFile(lexerTokens));
+
+ // TLexer.h
+ if (headerExtST != null) {
+ String header = g.name + suffix + headerExtST.render();
+ files.add(getOutputFile(header));
+ }
+ }
+
+ if ( g.tool.gen_listener ) {
+ // add generated listener; e.g., TListener.java
+ files.add(getOutputFile(generator.getListenerFileName()));
+ // add generated base listener; e.g., TBaseListener.java
+ files.add(getOutputFile(generator.getBaseListenerFileName()));
+ }
+
+ if ( g.tool.gen_visitor ) {
+ // add generated visitor; e.g., TVisitor.java
+ files.add(getOutputFile(generator.getVisitorFileName()));
+ // add generated base visitor; e.g., TBaseVisitor.java
+ files.add(getOutputFile(generator.getBaseVisitorFileName()));
+ }
+
+
+ // handle generated files for imported grammars
+ List<Grammar> imports = g.getAllImportedGrammars();
+ if ( imports!=null ) {
+ for (Grammar g : imports) {
+// File outputDir = tool.getOutputDirectory(g.fileName);
+// String fname = groomQualifiedFileName(outputDir.toString(), g.getRecognizerName() + extST.render());
+// files.add(new File(outputDir, fname));
+ files.add(getOutputFile(g.fileName));
+ }
+ }
+
+ if (files.isEmpty()) {
+ return null;
+ }
+ return files;
+ }
+
+ public File getOutputFile(String fileName) {
+ File outputDir = tool.getOutputDirectory(g.fileName);
+ if ( outputDir.toString().equals(".") ) {
+ // pay attention to -o then
+ outputDir = tool.getOutputDirectory(fileName);
+ }
+ if ( outputDir.toString().equals(".") ) {
+ return new File(fileName);
+ }
+ if (outputDir.getName().equals(".")) {
+ String fname = outputDir.toString();
+ int dot = fname.lastIndexOf('.');
+ outputDir = new File(outputDir.toString().substring(0,dot));
+ }
+
+ if (outputDir.getName().indexOf(' ') >= 0) { // has spaces?
+ String escSpaces = outputDir.toString().replace(" ", "\\ ");
+ outputDir = new File(escSpaces);
+ }
+ return new File(outputDir, fileName);
+ }
+
+ /**
+ * Return a list of File objects that name files ANTLR will read
+ * to process T.g; This can be .tokens files if the grammar uses the tokenVocab option
+ * as well as any imported grammar files.
+ */
+ public List<File> getDependenciesFileList() {
+ // Find all the things other than imported grammars
+ List<File> files = getNonImportDependenciesFileList();
+
+ // Handle imported grammars
+ List<Grammar> imports = g.getAllImportedGrammars();
+ if ( imports!=null ) {
+ for (Grammar g : imports) {
+ String libdir = tool.libDirectory;
+ String fileName = groomQualifiedFileName(libdir, g.fileName);
+ files.add(new File(fileName));
+ }
+ }
+
+ if (files.isEmpty()) {
+ return null;
+ }
+ return files;
+ }
+
+ /**
+ * Return a list of File objects that name files ANTLR will read
+ * to process T.g; This can only be .tokens files and only
+ * if they use the tokenVocab option.
+ *
+ * @return List of dependencies other than imported grammars
+ */
+ public List<File> getNonImportDependenciesFileList() {
+ List<File> files = new ArrayList<File>();
+
+ // handle token vocabulary loads
+ String tokenVocab = g.getOptionString("tokenVocab");
+ if (tokenVocab != null) {
+ String fileName =
+ tokenVocab + CodeGenerator.VOCAB_FILE_EXTENSION;
+ File vocabFile;
+ if ( tool.libDirectory.equals(".") ) {
+ vocabFile = new File(fileName);
+ }
+ else {
+ vocabFile = new File(tool.libDirectory, fileName);
+ }
+ files.add(vocabFile);
+ }
+
+ return files;
+ }
+
+ public ST getDependencies() {
+ loadDependencyTemplates();
+ ST dependenciesST = templates.getInstanceOf("dependencies");
+ dependenciesST.add("in", getDependenciesFileList());
+ dependenciesST.add("out", getGeneratedFileList());
+ dependenciesST.add("grammarFileName", g.fileName);
+ return dependenciesST;
+ }
+
+ public void loadDependencyTemplates() {
+ if (templates != null) return;
+ String fileName = "org/antlr/v4/tool/templates/depend.stg";
+ templates = new STGroupFile(fileName, "UTF-8");
+ }
+
+ public CodeGenerator getGenerator() {
+ return generator;
+ }
+
+ public String groomQualifiedFileName(String outputDir, String fileName) {
+ if (outputDir.equals(".")) {
+ return fileName;
+ }
+ else if (outputDir.indexOf(' ') >= 0) { // has spaces?
+ String escSpaces = outputDir.replace(" ", "\\ ");
+ return escSpaces + File.separator + fileName;
+ }
+ else {
+ return outputDir + File.separator + fileName;
+ }
+ }
+}
diff --git a/tool/src/org/antlr/v4/tool/DOTGenerator.java b/tool/src/org/antlr/v4/tool/DOTGenerator.java
new file mode 100644
index 0000000..740bfe4
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/DOTGenerator.java
@@ -0,0 +1,486 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.tool;
+
+import org.antlr.v4.misc.Utils;
+import org.antlr.v4.runtime.atn.ATNConfig;
+import org.antlr.v4.runtime.atn.ATNState;
+import org.antlr.v4.runtime.atn.AbstractPredicateTransition;
+import org.antlr.v4.runtime.atn.ActionTransition;
+import org.antlr.v4.runtime.atn.AtomTransition;
+import org.antlr.v4.runtime.atn.BlockEndState;
+import org.antlr.v4.runtime.atn.BlockStartState;
+import org.antlr.v4.runtime.atn.DecisionState;
+import org.antlr.v4.runtime.atn.NotSetTransition;
+import org.antlr.v4.runtime.atn.PlusBlockStartState;
+import org.antlr.v4.runtime.atn.PlusLoopbackState;
+import org.antlr.v4.runtime.atn.RangeTransition;
+import org.antlr.v4.runtime.atn.RuleStartState;
+import org.antlr.v4.runtime.atn.RuleStopState;
+import org.antlr.v4.runtime.atn.RuleTransition;
+import org.antlr.v4.runtime.atn.SetTransition;
+import org.antlr.v4.runtime.atn.StarBlockStartState;
+import org.antlr.v4.runtime.atn.StarLoopEntryState;
+import org.antlr.v4.runtime.atn.StarLoopbackState;
+import org.antlr.v4.runtime.atn.Transition;
+import org.antlr.v4.runtime.dfa.DFA;
+import org.antlr.v4.runtime.dfa.DFAState;
+import org.antlr.v4.runtime.misc.IntegerList;
+import org.stringtemplate.v4.ST;
+import org.stringtemplate.v4.STGroup;
+import org.stringtemplate.v4.STGroupFile;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+/** The DOT (part of graphviz) generation aspect. */
+public class DOTGenerator {
+ public static final boolean STRIP_NONREDUCED_STATES = false;
+
+ protected String arrowhead="normal";
+ protected String rankdir="LR";
+
+ /** Library of output templates; use {@code <attrname>} format. */
+ public static STGroup stlib = new STGroupFile("org/antlr/v4/tool/templates/dot/graphs.stg");
+
+ protected Grammar grammar;
+
+ /** This aspect is associated with a grammar */
+ public DOTGenerator(Grammar grammar) {
+ this.grammar = grammar;
+ }
+
+ public String getDOT(DFA dfa, boolean isLexer) {
+ if ( dfa.s0==null ) return null;
+
+ ST dot = stlib.getInstanceOf("dfa");
+ dot.add("name", "DFA"+dfa.decision);
+ dot.add("startState", dfa.s0.stateNumber);
+// dot.add("useBox", Tool.internalOption_ShowATNConfigsInDFA);
+ dot.add("rankdir", rankdir);
+
+ // define stop states first; seems to be a bug in DOT where doublecircle
+ for (DFAState d : dfa.states.keySet()) {
+ if ( !d.isAcceptState ) continue;
+ ST st = stlib.getInstanceOf("stopstate");
+ st.add("name", "s"+d.stateNumber);
+ st.add("label", getStateLabel(d));
+ dot.add("states", st);
+ }
+
+ for (DFAState d : dfa.states.keySet()) {
+ if ( d.isAcceptState ) continue;
+ if ( d.stateNumber == Integer.MAX_VALUE ) continue;
+ ST st = stlib.getInstanceOf("state");
+ st.add("name", "s"+d.stateNumber);
+ st.add("label", getStateLabel(d));
+ dot.add("states", st);
+ }
+
+ for (DFAState d : dfa.states.keySet()) {
+ if ( d.edges!=null ) {
+ for (int i = 0; i < d.edges.length; i++) {
+ DFAState target = d.edges[i];
+ if ( target==null) continue;
+ if ( target.stateNumber == Integer.MAX_VALUE ) continue;
+ int ttype = i-1; // we shift up for EOF as -1 for parser
+ String label = String.valueOf(ttype);
+ if ( isLexer ) label = "'"+getEdgeLabel(String.valueOf((char) i))+"'";
+ else if ( grammar!=null ) label = grammar.getTokenDisplayName(ttype);
+ ST st = stlib.getInstanceOf("edge");
+ st.add("label", label);
+ st.add("src", "s"+d.stateNumber);
+ st.add("target", "s"+target.stateNumber);
+ st.add("arrowhead", arrowhead);
+ dot.add("edges", st);
+ }
+ }
+ }
+
+ String output = dot.render();
+ return Utils.sortLinesInString(output);
+ }
+
+ protected String getStateLabel(DFAState s) {
+ if ( s==null ) return "null";
+ StringBuilder buf = new StringBuilder(250);
+ buf.append('s');
+ buf.append(s.stateNumber);
+ if ( s.isAcceptState ) {
+ buf.append("=>").append(s.prediction);
+ }
+ if ( s.requiresFullContext) {
+ buf.append("^");
+ }
+ if ( grammar!=null ) {
+ Set<Integer> alts = s.getAltSet();
+ if ( alts!=null ) {
+ buf.append("\\n");
+ // separate alts
+ IntegerList altList = new IntegerList();
+ altList.addAll(alts);
+ altList.sort();
+ Set<ATNConfig> configurations = s.configs;
+ for (int altIndex = 0; altIndex < altList.size(); altIndex++) {
+ int alt = altList.get(altIndex);
+ if ( altIndex>0 ) {
+ buf.append("\\n");
+ }
+ buf.append("alt");
+ buf.append(alt);
+ buf.append(':');
+ // get a list of configs for just this alt
+ // it will help us print better later
+ List<ATNConfig> configsInAlt = new ArrayList<ATNConfig>();
+ for (ATNConfig c : configurations) {
+ if (c.alt != alt) continue;
+ configsInAlt.add(c);
+ }
+ int n = 0;
+ for (int cIndex = 0; cIndex < configsInAlt.size(); cIndex++) {
+ ATNConfig c = configsInAlt.get(cIndex);
+ n++;
+ buf.append(c.toString(null, false));
+ if ( (cIndex+1)<configsInAlt.size() ) {
+ buf.append(", ");
+ }
+ if ( n%5==0 && (configsInAlt.size()-cIndex)>3 ) {
+ buf.append("\\n");
+ }
+ }
+ }
+ }
+ }
+ String stateLabel = buf.toString();
+ return stateLabel;
+ }
+
+ public String getDOT(ATNState startState) {
+ return getDOT(startState, false);
+ }
+
+ public String getDOT(ATNState startState, boolean isLexer) {
+ Set<String> ruleNames = grammar.rules.keySet();
+ String[] names = new String[ruleNames.size()+1];
+ int i = 0;
+ for (String s : ruleNames) names[i++] = s;
+ return getDOT(startState, names, isLexer);
+ }
+
+ /** Return a String containing a DOT description that, when displayed,
+ * will show the incoming state machine visually. All nodes reachable
+ * from startState will be included.
+ */
+ public String getDOT(ATNState startState, String[] ruleNames, boolean isLexer) {
+ if ( startState==null ) return null;
+
+ // The output DOT graph for visualization
+ Set<ATNState> markedStates = new HashSet<ATNState>();
+ ST dot = stlib.getInstanceOf("atn");
+ dot.add("startState", startState.stateNumber);
+ dot.add("rankdir", rankdir);
+
+ List<ATNState> work = new LinkedList<ATNState>();
+
+ work.add(startState);
+ while ( !work.isEmpty() ) {
+ ATNState s = work.get(0);
+ if ( markedStates.contains(s) ) { work.remove(0); continue; }
+ markedStates.add(s);
+
+ // don't go past end of rule node to the follow states
+ if ( s instanceof RuleStopState) continue;
+
+ // special case: if decision point, then line up the alt start states
+ // unless it's an end of block
+// if ( s instanceof BlockStartState ) {
+// ST rankST = stlib.getInstanceOf("decision-rank");
+// DecisionState alt = (DecisionState)s;
+// for (int i=0; i<alt.getNumberOfTransitions(); i++) {
+// ATNState target = alt.transition(i).target;
+// if ( target!=null ) {
+// rankST.add("states", target.stateNumber);
+// }
+// }
+// dot.add("decisionRanks", rankST);
+// }
+
+ // make a DOT edge for each transition
+ ST edgeST;
+ for (int i = 0; i < s.getNumberOfTransitions(); i++) {
+ Transition edge = s.transition(i);
+ if ( edge instanceof RuleTransition ) {
+ RuleTransition rr = ((RuleTransition)edge);
+ // don't jump to other rules, but display edge to follow node
+ edgeST = stlib.getInstanceOf("edge");
+
+ String label = "<" + ruleNames[rr.ruleIndex];
+ if (((RuleStartState)rr.target).isLeftRecursiveRule) {
+ label += "[" + rr.precedence + "]";
+ }
+ label += ">";
+
+ edgeST.add("label", label);
+ edgeST.add("src", "s"+s.stateNumber);
+ edgeST.add("target", "s"+rr.followState.stateNumber);
+ edgeST.add("arrowhead", arrowhead);
+ dot.add("edges", edgeST);
+ work.add(rr.followState);
+ continue;
+ }
+ if ( edge instanceof ActionTransition) {
+ edgeST = stlib.getInstanceOf("action-edge");
+ edgeST.add("label", getEdgeLabel(edge.toString()));
+ }
+ else if ( edge instanceof AbstractPredicateTransition ) {
+ edgeST = stlib.getInstanceOf("edge");
+ edgeST.add("label", getEdgeLabel(edge.toString()));
+ }
+ else if ( edge.isEpsilon() ) {
+ edgeST = stlib.getInstanceOf("epsilon-edge");
+ edgeST.add("label", getEdgeLabel(edge.toString()));
+ boolean loopback = false;
+ if (edge.target instanceof PlusBlockStartState) {
+ loopback = s.equals(((PlusBlockStartState)edge.target).loopBackState);
+ }
+ else if (edge.target instanceof StarLoopEntryState) {
+ loopback = s.equals(((StarLoopEntryState)edge.target).loopBackState);
+ }
+ edgeST.add("loopback", loopback);
+ }
+ else if ( edge instanceof AtomTransition ) {
+ edgeST = stlib.getInstanceOf("edge");
+ AtomTransition atom = (AtomTransition)edge;
+ String label = String.valueOf(atom.label);
+ if ( isLexer ) label = "'"+getEdgeLabel(String.valueOf((char)atom.label))+"'";
+ else if ( grammar!=null ) label = grammar.getTokenDisplayName(atom.label);
+ edgeST.add("label", getEdgeLabel(label));
+ }
+ else if ( edge instanceof SetTransition ) {
+ edgeST = stlib.getInstanceOf("edge");
+ SetTransition set = (SetTransition)edge;
+ String label = set.label().toString();
+ if ( isLexer ) label = set.label().toString(true);
+ else if ( grammar!=null ) label = set.label().toString(grammar.getVocabulary());
+ if ( edge instanceof NotSetTransition ) label = "~"+label;
+ edgeST.add("label", getEdgeLabel(label));
+ }
+ else if ( edge instanceof RangeTransition ) {
+ edgeST = stlib.getInstanceOf("edge");
+ RangeTransition range = (RangeTransition)edge;
+ String label = range.label().toString();
+ if ( isLexer ) label = range.toString();
+ else if ( grammar!=null ) label = range.label().toString(grammar.getVocabulary());
+ edgeST.add("label", getEdgeLabel(label));
+ }
+ else {
+ edgeST = stlib.getInstanceOf("edge");
+ edgeST.add("label", getEdgeLabel(edge.toString()));
+ }
+ edgeST.add("src", "s"+s.stateNumber);
+ edgeST.add("target", "s"+edge.target.stateNumber);
+ edgeST.add("arrowhead", arrowhead);
+ if (s.getNumberOfTransitions() > 1) {
+ edgeST.add("transitionIndex", i);
+ } else {
+ edgeST.add("transitionIndex", false);
+ }
+ dot.add("edges", edgeST);
+ work.add(edge.target);
+ }
+ }
+
+ // define nodes we visited (they will appear first in DOT output)
+ // this is an example of ST's lazy eval :)
+ // define stop state first; seems to be a bug in DOT where doublecircle
+ // shape only works if we define them first. weird.
+// ATNState stopState = startState.atn.ruleToStopState.get(startState.rule);
+// if ( stopState!=null ) {
+// ST st = stlib.getInstanceOf("stopstate");
+// st.add("name", "s"+stopState.stateNumber);
+// st.add("label", getStateLabel(stopState));
+// dot.add("states", st);
+// }
+ for (ATNState s : markedStates) {
+ if ( !(s instanceof RuleStopState) ) continue;
+ ST st = stlib.getInstanceOf("stopstate");
+ st.add("name", "s"+s.stateNumber);
+ st.add("label", getStateLabel(s));
+ dot.add("states", st);
+ }
+
+ for (ATNState s : markedStates) {
+ if ( s instanceof RuleStopState ) continue;
+ ST st = stlib.getInstanceOf("state");
+ st.add("name", "s"+s.stateNumber);
+ st.add("label", getStateLabel(s));
+ st.add("transitions", s.getTransitions());
+ dot.add("states", st);
+ }
+
+ return dot.render();
+ }
+
+
+ /** Do a depth-first walk of the state machine graph and
+ * fill a DOT description template. Keep filling the
+ * states and edges attributes. We know this is an ATN
+ * for a rule so don't traverse edges to other rules and
+ * don't go past rule end state.
+ */
+// protected void walkRuleATNCreatingDOT(ST dot,
+// ATNState s)
+// {
+// if ( markedStates.contains(s) ) {
+// return; // already visited this node
+// }
+//
+// markedStates.add(s.stateNumber); // mark this node as completed.
+//
+// // first add this node
+// ST stateST;
+// if ( s instanceof RuleStopState ) {
+// stateST = stlib.getInstanceOf("stopstate");
+// }
+// else {
+// stateST = stlib.getInstanceOf("state");
+// }
+// stateST.add("name", getStateLabel(s));
+// dot.add("states", stateST);
+//
+// if ( s instanceof RuleStopState ) {
+// return; // don't go past end of rule node to the follow states
+// }
+//
+// // special case: if decision point, then line up the alt start states
+// // unless it's an end of block
+// if ( s instanceof DecisionState ) {
+// GrammarAST n = ((ATNState)s).ast;
+// if ( n!=null && s instanceof BlockEndState ) {
+// ST rankST = stlib.getInstanceOf("decision-rank");
+// ATNState alt = (ATNState)s;
+// while ( alt!=null ) {
+// rankST.add("states", getStateLabel(alt));
+// if ( alt.transition(1) !=null ) {
+// alt = (ATNState)alt.transition(1).target;
+// }
+// else {
+// alt=null;
+// }
+// }
+// dot.add("decisionRanks", rankST);
+// }
+// }
+//
+// // make a DOT edge for each transition
+// ST edgeST = null;
+// for (int i = 0; i < s.getNumberOfTransitions(); i++) {
+// Transition edge = (Transition) s.transition(i);
+// if ( edge instanceof RuleTransition ) {
+// RuleTransition rr = ((RuleTransition)edge);
+// // don't jump to other rules, but display edge to follow node
+// edgeST = stlib.getInstanceOf("edge");
+// if ( rr.rule.g != grammar ) {
+// edgeST.add("label", "<"+rr.rule.g.name+"."+rr.rule.name+">");
+// }
+// else {
+// edgeST.add("label", "<"+rr.rule.name+">");
+// }
+// edgeST.add("src", getStateLabel(s));
+// edgeST.add("target", getStateLabel(rr.followState));
+// edgeST.add("arrowhead", arrowhead);
+// dot.add("edges", edgeST);
+// walkRuleATNCreatingDOT(dot, rr.followState);
+// continue;
+// }
+// if ( edge instanceof ActionTransition ) {
+// edgeST = stlib.getInstanceOf("action-edge");
+// }
+// else if ( edge instanceof PredicateTransition ) {
+// edgeST = stlib.getInstanceOf("edge");
+// }
+// else if ( edge.isEpsilon() ) {
+// edgeST = stlib.getInstanceOf("epsilon-edge");
+// }
+// else {
+// edgeST = stlib.getInstanceOf("edge");
+// }
+// edgeST.add("label", getEdgeLabel(edge.toString(grammar)));
+// edgeST.add("src", getStateLabel(s));
+// edgeST.add("target", getStateLabel(edge.target));
+// edgeST.add("arrowhead", arrowhead);
+// dot.add("edges", edgeST);
+// walkRuleATNCreatingDOT(dot, edge.target); // keep walkin'
+// }
+// }
+
+ /** Fix edge strings so they print out in DOT properly;
+ * generate any gated predicates on edge too.
+ */
+ protected String getEdgeLabel(String label) {
+ label = label.replace("\\", "\\\\");
+ label = label.replace("\"", "\\\"");
+ label = label.replace("\n", "\\\\n");
+ label = label.replace("\r", "");
+ return label;
+ }
+
+ protected String getStateLabel(ATNState s) {
+ if ( s==null ) return "null";
+ String stateLabel = "";
+
+ if (s instanceof BlockStartState) {
+ stateLabel += "&rarr;\\n";
+ }
+ else if (s instanceof BlockEndState) {
+ stateLabel += "&larr;\\n";
+ }
+
+ stateLabel += String.valueOf(s.stateNumber);
+
+ if (s instanceof PlusBlockStartState || s instanceof PlusLoopbackState) {
+ stateLabel += "+";
+ }
+ else if (s instanceof StarBlockStartState || s instanceof StarLoopEntryState || s instanceof StarLoopbackState) {
+ stateLabel += "*";
+ }
+
+ if ( s instanceof DecisionState && ((DecisionState)s).decision>=0 ) {
+ stateLabel = stateLabel+"\\nd="+((DecisionState)s).decision;
+ }
+
+ return stateLabel;
+ }
+
+}
diff --git a/tool/src/org/antlr/v4/tool/DefaultToolListener.java b/tool/src/org/antlr/v4/tool/DefaultToolListener.java
new file mode 100644
index 0000000..2005c85
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/DefaultToolListener.java
@@ -0,0 +1,69 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.tool;
+
+import org.antlr.v4.Tool;
+import org.stringtemplate.v4.ST;
+
+/** */
+public class DefaultToolListener implements ANTLRToolListener {
+ public Tool tool;
+
+ public DefaultToolListener(Tool tool) { this.tool = tool; }
+
+ @Override
+ public void info(String msg) {
+ if (tool.errMgr.formatWantsSingleLineMessage()) {
+ msg = msg.replace('\n', ' ');
+ }
+ System.out.println(msg);
+ }
+
+ @Override
+ public void error(ANTLRMessage msg) {
+ ST msgST = tool.errMgr.getMessageTemplate(msg);
+ String outputMsg = msgST.render();
+ if (tool.errMgr.formatWantsSingleLineMessage()) {
+ outputMsg = outputMsg.replace('\n', ' ');
+ }
+ System.err.println(outputMsg);
+ }
+
+ @Override
+ public void warning(ANTLRMessage msg) {
+ ST msgST = tool.errMgr.getMessageTemplate(msg);
+ String outputMsg = msgST.render();
+ if (tool.errMgr.formatWantsSingleLineMessage()) {
+ outputMsg = outputMsg.replace('\n', ' ');
+ }
+ System.err.println(outputMsg);
+ }
+}
diff --git a/tool/src/org/antlr/v4/tool/ErrorManager.java b/tool/src/org/antlr/v4/tool/ErrorManager.java
new file mode 100644
index 0000000..983c41b
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/ErrorManager.java
@@ -0,0 +1,322 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.tool;
+
+import org.antlr.v4.Tool;
+import org.stringtemplate.v4.ST;
+import org.stringtemplate.v4.STGroup;
+import org.stringtemplate.v4.STGroupFile;
+import org.stringtemplate.v4.misc.ErrorBuffer;
+
+import java.io.File;
+import java.net.URL;
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.Locale;
+import java.util.Set;
+
+public class ErrorManager {
+ public static final String FORMATS_DIR = "org/antlr/v4/tool/templates/messages/formats/";
+
+ public Tool tool;
+ public int errors;
+ public int warnings;
+
+ /** All errors that have been generated */
+ public Set<ErrorType> errorTypes = EnumSet.noneOf(ErrorType.class);
+
+ /** The group of templates that represent the current message format. */
+ STGroup format;
+
+ /** Messages should be sensitive to the locale. */
+ Locale locale;
+ String formatName;
+
+ ErrorBuffer initSTListener = new ErrorBuffer();
+
+ public ErrorManager(Tool tool) {
+ this.tool = tool;
+ }
+
+ public void resetErrorState() {
+ errors = 0;
+ warnings = 0;
+ }
+
+ public ST getMessageTemplate(ANTLRMessage msg) {
+ ST messageST = msg.getMessageTemplate(tool.longMessages);
+ ST locationST = getLocationFormat();
+ ST reportST = getReportFormat(msg.getErrorType().severity);
+ ST messageFormatST = getMessageFormat();
+
+ boolean locationValid = false;
+ if (msg.line != -1) {
+ locationST.add("line", msg.line);
+ locationValid = true;
+ }
+ if (msg.charPosition != -1) {
+ locationST.add("column", msg.charPosition);
+ locationValid = true;
+ }
+ if (msg.fileName != null) {
+ File f = new File(msg.fileName);
+ // Don't show path to file in messages; too long.
+ String displayFileName = msg.fileName;
+ if ( f.exists() ) {
+ displayFileName = f.getName();
+ }
+ locationST.add("file", displayFileName);
+ locationValid = true;
+ }
+
+ messageFormatST.add("id", msg.getErrorType().code);
+ messageFormatST.add("text", messageST);
+
+ if (locationValid) reportST.add("location", locationST);
+ reportST.add("message", messageFormatST);
+ //((DebugST)reportST).inspect();
+// reportST.impl.dump();
+ return reportST;
+ }
+
+ /** Return a StringTemplate that refers to the current format used for
+ * emitting messages.
+ */
+ public ST getLocationFormat() {
+ return format.getInstanceOf("location");
+ }
+
+ public ST getReportFormat(ErrorSeverity severity) {
+ ST st = format.getInstanceOf("report");
+ st.add("type", severity.getText());
+ return st;
+ }
+
+ public ST getMessageFormat() {
+ return format.getInstanceOf("message");
+ }
+ public boolean formatWantsSingleLineMessage() {
+ return format.getInstanceOf("wantsSingleLineMessage").render().equals("true");
+ }
+
+ public void info(String msg) { tool.info(msg); }
+
+ public void syntaxError(ErrorType etype,
+ String fileName,
+ org.antlr.runtime.Token token,
+ org.antlr.runtime.RecognitionException antlrException,
+ Object... args)
+ {
+ ANTLRMessage msg = new GrammarSyntaxMessage(etype,fileName,token,antlrException,args);
+ emit(etype, msg);
+ }
+
+ public static void fatalInternalError(String error, Throwable e) {
+ internalError(error, e);
+ throw new RuntimeException(error, e);
+ }
+
+ public static void internalError(String error, Throwable e) {
+ StackTraceElement location = getLastNonErrorManagerCodeLocation(e);
+ internalError("Exception "+e+"@"+location+": "+error);
+ }
+
+ public static void internalError(String error) {
+ StackTraceElement location =
+ getLastNonErrorManagerCodeLocation(new Exception());
+ String msg = location+": "+error;
+ System.err.println("internal error: "+msg);
+ }
+
+ /**
+ * Raise a predefined message with some number of paramters for the StringTemplate but for which there
+ * is no location information possible.
+ * @param errorType The Message Descriptor
+ * @param args The arguments to pass to the StringTemplate
+ */
+ public void toolError(ErrorType errorType, Object... args) {
+ toolError(errorType, null, args);
+ }
+
+ public void toolError(ErrorType errorType, Throwable e, Object... args) {
+ ToolMessage msg = new ToolMessage(errorType, e, args);
+ emit(errorType, msg);
+ }
+
+ public void grammarError(ErrorType etype,
+ String fileName,
+ org.antlr.runtime.Token token,
+ Object... args)
+ {
+ ANTLRMessage msg = new GrammarSemanticsMessage(etype,fileName,token,args);
+ emit(etype, msg);
+
+ }
+
+ public void leftRecursionCycles(String fileName, Collection<? extends Collection<Rule>> cycles) {
+ errors++;
+ ANTLRMessage msg = new LeftRecursionCyclesMessage(fileName, cycles);
+ tool.error(msg);
+ }
+
+ public int getNumErrors() {
+ return errors;
+ }
+
+ /** Return first non ErrorManager code location for generating messages */
+ private static StackTraceElement getLastNonErrorManagerCodeLocation(Throwable e) {
+ StackTraceElement[] stack = e.getStackTrace();
+ int i = 0;
+ for (; i < stack.length; i++) {
+ StackTraceElement t = stack[i];
+ if (!t.toString().contains("ErrorManager")) {
+ break;
+ }
+ }
+ StackTraceElement location = stack[i];
+ return location;
+ }
+
+ // S U P P O R T C O D E
+
+ @SuppressWarnings("fallthrough")
+ public void emit(ErrorType etype, ANTLRMessage msg) {
+ switch ( etype.severity ) {
+ case WARNING_ONE_OFF:
+ if ( errorTypes.contains(etype) ) break;
+ // fall thru
+ case WARNING:
+ warnings++;
+ tool.warning(msg);
+ break;
+ case ERROR_ONE_OFF:
+ if ( errorTypes.contains(etype) ) break;
+ // fall thru
+ case ERROR:
+ errors++;
+ tool.error(msg);
+ break;
+ }
+ errorTypes.add(etype);
+ }
+
+ /** The format gets reset either from the Tool if the user supplied a command line option to that effect
+ * Otherwise we just use the default "antlr".
+ */
+ public void setFormat(String formatName) {
+ this.formatName = formatName;
+ String fileName = FORMATS_DIR +formatName+STGroup.GROUP_FILE_EXTENSION;
+ ClassLoader cl = Thread.currentThread().getContextClassLoader();
+ URL url = cl.getResource(fileName);
+ if ( url==null ) {
+ cl = ErrorManager.class.getClassLoader();
+ url = cl.getResource(fileName);
+ }
+ if ( url==null && formatName.equals("antlr") ) {
+ rawError("ANTLR installation corrupted; cannot find ANTLR messages format file "+fileName);
+ panic();
+ }
+ else if ( url==null ) {
+ rawError("no such message format file "+fileName+" retrying with default ANTLR format");
+ setFormat("antlr"); // recurse on this rule, trying the default message format
+ return;
+ }
+
+ format = new STGroupFile(fileName, "UTF-8");
+ format.load();
+
+ if ( !initSTListener.errors.isEmpty() ) {
+ rawError("ANTLR installation corrupted; can't load messages format file:\n"+
+ initSTListener.toString());
+ panic();
+ }
+
+ boolean formatOK = verifyFormat();
+ if ( !formatOK && formatName.equals("antlr") ) {
+ rawError("ANTLR installation corrupted; ANTLR messages format file "+formatName+".stg incomplete");
+ panic();
+ }
+ else if ( !formatOK ) {
+ setFormat("antlr"); // recurse on this rule, trying the default message format
+ }
+ }
+
+ /** Verify the message format template group */
+ protected boolean verifyFormat() {
+ boolean ok = true;
+ if (!format.isDefined("location")) {
+ System.err.println("Format template 'location' not found in " + formatName);
+ ok = false;
+ }
+ if (!format.isDefined("message")) {
+ System.err.println("Format template 'message' not found in " + formatName);
+ ok = false;
+ }
+ if (!format.isDefined("report")) {
+ System.err.println("Format template 'report' not found in " + formatName);
+ ok = false;
+ }
+ return ok;
+ }
+
+ /** If there are errors during ErrorManager init, we have no choice
+ * but to go to System.err.
+ */
+ static void rawError(String msg) {
+ System.err.println(msg);
+ }
+
+ static void rawError(String msg, Throwable e) {
+ rawError(msg);
+ e.printStackTrace(System.err);
+ }
+
+ public void panic(ErrorType errorType, Object... args) {
+ ToolMessage msg = new ToolMessage(errorType, args);
+ ST msgST = getMessageTemplate(msg);
+ String outputMsg = msgST.render();
+ if ( formatWantsSingleLineMessage() ) {
+ outputMsg = outputMsg.replace('\n', ' ');
+ }
+ panic(outputMsg);
+ }
+
+ public static void panic(String msg) {
+ rawError(msg);
+ panic();
+ }
+
+ public static void panic() {
+ // can't call tool.panic since there may be multiple tools; just
+ // one error manager
+ throw new Error("ANTLR ErrorManager panic");
+ }
+}
diff --git a/tool/src/org/antlr/v4/tool/ErrorSeverity.java b/tool/src/org/antlr/v4/tool/ErrorSeverity.java
new file mode 100644
index 0000000..f942d3e
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/ErrorSeverity.java
@@ -0,0 +1,68 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.v4.tool;
+
+/**
+ * Abstracts away the definition of Message severity and the text that should
+ * display to represent that severity if there is no StringTemplate available
+ * to do it.
+ *
+ * @author Jim Idle - Temporal Wave LLC (jimi@temporal-wave.com)
+ */
+public enum ErrorSeverity {
+ INFO ("info"),
+ WARNING ("warning"),
+ WARNING_ONE_OFF ("warning"),
+ ERROR ("error"),
+ ERROR_ONE_OFF ("error"),
+ FATAL ("fatal"), // TODO: add fatal for which phase? sync with ErrorManager
+ ;
+
+ /**
+ * The text version of the ENUM value, used for display purposes
+ */
+ private final String text;
+
+ /**
+ * Standard getter method for the text that should be displayed in order to
+ * represent the severity to humans and product modelers.
+ *
+ * @return The human readable string representing the severity level
+ */
+ public String getText() { return text; }
+
+ /**
+ * Standard constructor to build an instance of the Enum entries
+ *
+ * @param text The human readable string representing the serverity level
+ */
+ private ErrorSeverity(String text) { this.text = text; }
+}
+
diff --git a/tool/src/org/antlr/v4/tool/ErrorType.java b/tool/src/org/antlr/v4/tool/ErrorType.java
new file mode 100644
index 0000000..4868931
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/ErrorType.java
@@ -0,0 +1,1100 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.v4.tool;
+
+import org.antlr.v4.Tool;
+import org.antlr.v4.runtime.Lexer;
+
+/**
+ * A complex enumeration of all the error messages that the tool can issue.
+ * <p/>
+ * When adding error messages, also add a description of the message to the
+ * Wiki with a location under the Wiki page
+ * <a href="http://www.antlr.org/wiki/display/ANTLR4/Errors+Reported+by+the+ANTLR+Tool">Errors Reported by the ANTLR Tool</a>.
+ *
+ * @author Jim Idle <jimi@temporal-wave.com>, Terence Parr
+ * @since 4.0
+ */
+public enum ErrorType {
+ /*
+ * Tool errors
+ */
+
+ /**
+ * Compiler Error 1.
+ *
+ * <p>cannot write file <em>filename</em>: <em>reason</em></p>
+ */
+ CANNOT_WRITE_FILE(1, "cannot write file <arg>: <arg2>", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 2.
+ *
+ * <p>unknown command-line option <em>option</em></p>
+ */
+ INVALID_CMDLINE_ARG(2, "unknown command-line option <arg>", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 3.
+ *
+ * <p>cannot find tokens file <em>filename</em></p>
+ */
+ CANNOT_FIND_TOKENS_FILE_GIVEN_ON_CMDLINE(3, "cannot find tokens file <arg> given for <arg2>", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 4.
+ *
+ * <p>cannot find tokens file <em>filename</em>: <em>reason</em></p>
+ */
+ ERROR_READING_TOKENS_FILE(4, "error reading tokens file <arg>: <arg2>", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 5.
+ *
+ * <p>directory not found: <em>directory</em></p>
+ */
+ DIR_NOT_FOUND(5, "directory not found: <arg>", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 6.
+ *
+ * <p>output directory is a file: <em>filename</em></p>
+ */
+ OUTPUT_DIR_IS_FILE(6, "output directory is a file: <arg>", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 7.
+ *
+ * <p>cannot find or open file: <em>filename</em></p>
+ */
+ CANNOT_OPEN_FILE(7, "cannot find or open file: <arg><if(exception&&verbose)>; reason: <exception><endif>", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 8.
+ *
+ * <p>
+ * grammar name <em>name</em> and file name <em>filename</em> differ</p>
+ */
+ FILE_AND_GRAMMAR_NAME_DIFFER(8, "grammar name <arg> and file name <arg2> differ", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 9.
+ *
+ * <p>invalid {@code -Dname=value} syntax: <em>syntax</em></p>
+ */
+ BAD_OPTION_SET_SYNTAX(9, "invalid -Dname=value syntax: <arg>", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 10.
+ *
+ * <p>warning treated as error</p>
+ */
+ WARNING_TREATED_AS_ERROR(10, "warning treated as error", ErrorSeverity.ERROR_ONE_OFF),
+ /**
+ * Compiler Error 11.
+ *
+ * <p>cannot find tokens file <em>filename</em>: <em>reason</em></p>
+ */
+ ERROR_READING_IMPORTED_GRAMMAR(11, "error reading imported grammar <arg> referenced in <arg2>", ErrorSeverity.ERROR),
+
+ /**
+ * Compiler Error 20.
+ *
+ * <p>internal error: <em>message</em></p>
+ */
+ INTERNAL_ERROR(20, "internal error: <arg> <arg2><if(exception&&verbose)>: <exception>" +
+ "<stackTrace; separator=\"\\n\"><endif>", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 21.
+ *
+ * <p>.tokens file syntax error <em>filename</em>: <em>message</em></p>
+ */
+ TOKENS_FILE_SYNTAX_ERROR(21, ".tokens file syntax error <arg>:<arg2>", ErrorSeverity.ERROR),
+ /**
+ * Compiler Warning 22.
+ *
+ * <p>template error: <em>message</em></p>
+ */
+ STRING_TEMPLATE_WARNING(22, "template error: <arg> <arg2><if(exception&&verbose)>: <exception>" +
+ "<stackTrace; separator=\"\\n\"><endif>", ErrorSeverity.WARNING),
+
+ /*
+ * Code generation errors
+ */
+
+ /**
+ * Compiler Error 30.
+ *
+ * <p>can't find code generation templates: <em>group</em></p>
+ */
+ MISSING_CODE_GEN_TEMPLATES(30, "can't find code generation templates: <arg>", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 31.
+ *
+ * <p>
+ * ANTLR cannot generate <em>language</em> code as of version
+ * <em>version</em></p>
+ */
+ CANNOT_CREATE_TARGET_GENERATOR(31, "ANTLR cannot generate <arg> code as of version "+ Tool.VERSION, ErrorSeverity.ERROR_ONE_OFF),
+ /**
+ * Compiler Error 32.
+ *
+ * <p>
+ * code generation template <em>template</em> has missing, misnamed, or
+ * incomplete arg list; missing <em>field</em></p>
+ */
+ CODE_TEMPLATE_ARG_ISSUE(32, "code generation template <arg> has missing, misnamed, or incomplete arg list; missing <arg2>", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 33.
+ *
+ * <p>missing code generation template <em>template</em></p>
+ */
+ CODE_GEN_TEMPLATES_INCOMPLETE(33, "missing code generation template <arg>", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 34.
+ *
+ * <p>
+ * no mapping to template name for output model class <em>class</em></p>
+ */
+ NO_MODEL_TO_TEMPLATE_MAPPING(34, "no mapping to template name for output model class <arg>", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 35.
+ *
+ * <p>templates/target and tool aren't compatible</p>
+ */
+ INCOMPATIBLE_TOOL_AND_TEMPLATES(35, "<arg3> code generation target requires ANTLR <arg2>; it can't be loaded by the current ANTLR <arg>", ErrorSeverity.ERROR),
+
+ /*
+ * Grammar errors
+ */
+
+ /**
+ * Compiler Error 50.
+ *
+ * <p>syntax error: <em>message</em></p>
+ */
+ SYNTAX_ERROR(50, "syntax error: <arg>", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 51.
+ *
+ * <p>rule <em>rule</em> redefinition; previous at line <em>line</em></p>
+ */
+ RULE_REDEFINITION(51, "rule <arg> redefinition; previous at line <arg2>", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 52.
+ *
+ * <p>lexer rule <em>rule</em> not allowed in parser</p>
+ */
+ LEXER_RULES_NOT_ALLOWED(52, "lexer rule <arg> not allowed in parser", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 53.
+ *
+ * <p>parser rule <em>rule</em> not allowed in lexer</p>
+ */
+ PARSER_RULES_NOT_ALLOWED(53, "parser rule <arg> not allowed in lexer", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 54.
+ *
+ * <p>
+ * repeated grammar prequel spec ({@code options}, {@code tokens}, or
+ * {@code import}); please merge</p>
+ */
+ REPEATED_PREQUEL(54, "repeated grammar prequel spec (options, tokens, or import); please merge", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 56.
+ *
+ * <p>reference to undefined rule: <em>rule</em></p>
+ *
+ * @see #PARSER_RULE_REF_IN_LEXER_RULE
+ */
+ UNDEFINED_RULE_REF(56, "reference to undefined rule: <arg>", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 57.
+ *
+ * <p>
+ * reference to undefined rule <em>rule</em> in non-local ref
+ * <em>reference</em></p>
+ */
+ UNDEFINED_RULE_IN_NONLOCAL_REF(57, "reference to undefined rule <arg> in non-local ref <arg3>", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 60.
+ *
+ * <p>token names must start with an uppercase letter: <em>name</em></p>
+ */
+ TOKEN_NAMES_MUST_START_UPPER(60, "token names must start with an uppercase letter: <arg>", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 63.
+ *
+ * <p>
+ * unknown attribute reference <em>attribute</em> in
+ * <em>expression</em></p>
+ */
+ UNKNOWN_SIMPLE_ATTRIBUTE(63, "unknown attribute reference <arg> in <arg2>", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 64.
+ *
+ * <p>
+ * parameter <em>parameter</em> of rule <em>rule</em> is not accessible
+ * in this scope: <em>expression</em></p>
+ */
+ INVALID_RULE_PARAMETER_REF(64, "parameter <arg> of rule <arg2> is not accessible in this scope: <arg3>", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 65.
+ *
+ * <p>
+ * unknown attribute <em>attribute</em> for rule <em>rule</em> in
+ * <em>expression</em></p>
+ */
+ UNKNOWN_RULE_ATTRIBUTE(65, "unknown attribute <arg> for rule <arg2> in <arg3>", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 66.
+ *
+ * <p>
+ * attribute <em>attribute</em> isn't a valid property in
+ * <em>expression</em></p>
+ */
+ UNKNOWN_ATTRIBUTE_IN_SCOPE(66, "attribute <arg> isn't a valid property in <arg2>", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 67.
+ *
+ * <p>
+ * missing attribute access on rule reference <em>rule</em> in
+ * <em>expression</em></p>
+ */
+ ISOLATED_RULE_REF(67, "missing attribute access on rule reference <arg> in <arg2>", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 69.
+ *
+ * <p>label <em>label</em> conflicts with rule with same name</p>
+ */
+ LABEL_CONFLICTS_WITH_RULE(69, "label <arg> conflicts with rule with same name", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 70.
+ *
+ * <p>label <em>label</em> conflicts with token with same name</p>
+ */
+ LABEL_CONFLICTS_WITH_TOKEN(70, "label <arg> conflicts with token with same name", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 72.
+ *
+ * <p>label <em>label</em> conflicts with parameter with same name</p>
+ */
+ LABEL_CONFLICTS_WITH_ARG(72, "label <arg> conflicts with parameter with same name", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 73.
+ *
+ * <p>label <em>label</em> conflicts with return value with same name</p>
+ */
+ LABEL_CONFLICTS_WITH_RETVAL(73, "label <arg> conflicts with return value with same name", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 74.
+ *
+ * <p>label <em>label</em> conflicts with local with same name</p>
+ */
+ LABEL_CONFLICTS_WITH_LOCAL(74, "label <arg> conflicts with local with same name", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 75.
+ *
+ * <p>
+ * label <em>label</em> type mismatch with previous definition:
+ * <em>message</em></p>
+ */
+ LABEL_TYPE_CONFLICT(75, "label <arg> type mismatch with previous definition: <arg2>", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 76.
+ *
+ * <p>
+ * return value <em>name</em> conflicts with parameter with same name</p>
+ */
+ RETVAL_CONFLICTS_WITH_ARG(76, "return value <arg> conflicts with parameter with same name", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 79.
+ *
+ * <p>missing arguments(s) on rule reference: <em>rule</em></p>
+ */
+ MISSING_RULE_ARGS(79, "missing arguments(s) on rule reference: <arg>", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 80.
+ *
+ * <p>rule <em>rule</em> has no defined parameters</p>
+ */
+ RULE_HAS_NO_ARGS(80, "rule <arg> has no defined parameters", ErrorSeverity.ERROR),
+ /**
+ * Compiler Warning 83.
+ *
+ * <p>unsupported option <em>option</em></p>
+ */
+ ILLEGAL_OPTION(83, "unsupported option <arg>", ErrorSeverity.WARNING),
+ /**
+ * Compiler Warning 84.
+ *
+ * <p>unsupported option value <em>name</em>=<em>value</em></p>
+ */
+ ILLEGAL_OPTION_VALUE(84, "unsupported option value <arg>=<arg2>", ErrorSeverity.WARNING),
+ /**
+ * Compiler Error 94.
+ *
+ * <p>redefinition of <em>action</em> action</p>
+ */
+ ACTION_REDEFINITION(94, "redefinition of <arg> action", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 99.
+ *
+ * <p>This error may take any of the following forms.</p>
+ *
+ * <ul>
+ * <li>grammar <em>grammar</em> has no rules</li>
+ * <li>implicitly generated grammar <em>grammar</em> has no rules</li>
+ * </ul>
+ */
+ NO_RULES(99, "<if(arg2.implicitLexerOwner)>implicitly generated <endif>grammar <arg> has no rules", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 105.
+ *
+ * <p>
+ * reference to undefined grammar in rule reference:
+ * <em>grammar</em>.<em>rule</em></p>
+ */
+ NO_SUCH_GRAMMAR_SCOPE(105, "reference to undefined grammar in rule reference: <arg>.<arg2>", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 106.
+ *
+ * <p>rule <em>rule</em> is not defined in grammar <em>grammar</em></p>
+ */
+ NO_SUCH_RULE_IN_SCOPE(106, "rule <arg2> is not defined in grammar <arg>", ErrorSeverity.ERROR),
+ /**
+ * Compiler Warning 108.
+ *
+ * <p>token name <em>Token</em> is already defined</p>
+ */
+ TOKEN_NAME_REASSIGNMENT(108, "token name <arg> is already defined", ErrorSeverity.WARNING),
+ /**
+ * Compiler Warning 109.
+ *
+ * <p>options ignored in imported grammar <em>grammar</em></p>
+ */
+ OPTIONS_IN_DELEGATE(109, "options ignored in imported grammar <arg>", ErrorSeverity.WARNING),
+ /**
+ * Compiler Error 110.
+ *
+ * <p>
+ * can't find or load grammar <em>grammar</em> from
+ * <em>filename</em></p>
+ */
+ CANNOT_FIND_IMPORTED_GRAMMAR(110, "can't find or load grammar <arg>", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 111.
+ *
+ * <p>
+ * <em>grammartype</em> grammar <em>grammar1</em> cannot import
+ * <em>grammartype</em> grammar <em>grammar2</em></p>
+ */
+ INVALID_IMPORT(111, "<arg.typeString> grammar <arg.name> cannot import <arg2.typeString> grammar <arg2.name>", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 113.
+ *
+ * <p>
+ * <em>grammartype</em> grammar <em>grammar1</em> and imported
+ * <em>grammartype</em> grammar <em>grammar2</em> both generate
+ * <em>recognizer</em></p>
+ */
+ IMPORT_NAME_CLASH(113, "<arg.typeString> grammar <arg.name> and imported <arg2.typeString> grammar <arg2.name> both generate <arg2.recognizerName>", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 160.
+ *
+ * <p>cannot find tokens file <em>filename</em></p>
+ */
+ CANNOT_FIND_TOKENS_FILE_REFD_IN_GRAMMAR(160, "cannot find tokens file <arg>", ErrorSeverity.ERROR),
+ /**
+ * Compiler Warning 118.
+ *
+ * <p>
+ * all operators of alt <em>alt</em> of left-recursive rule must have same
+ * associativity</p>
+ *
+ * @deprecated This warning is no longer applicable with the current syntax for specifying associativity.
+ */
+ @Deprecated
+ ALL_OPS_NEED_SAME_ASSOC(118, "all operators of alt <arg> of left-recursive rule must have same associativity", ErrorSeverity.WARNING),
+ /**
+ * Compiler Error 119.
+ *
+ * <p>
+ * The following sets of rules are mutually left-recursive
+ * <em>[rules]</em></p>
+ */
+ LEFT_RECURSION_CYCLES(119, "The following sets of rules are mutually left-recursive <arg:{c| [<c:{r|<r.name>}; separator=\", \">]}; separator=\" and \">", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 120.
+ *
+ * <p>lexical modes are only allowed in lexer grammars</p>
+ */
+ MODE_NOT_IN_LEXER(120, "lexical modes are only allowed in lexer grammars", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 121.
+ *
+ * <p>cannot find an attribute name in attribute declaration</p>
+ */
+ CANNOT_FIND_ATTRIBUTE_NAME_IN_DECL(121, "cannot find an attribute name in attribute declaration", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 122.
+ *
+ * <p>rule <em>rule</em>: must label all alternatives or none</p>
+ */
+ RULE_WITH_TOO_FEW_ALT_LABELS(122, "rule <arg>: must label all alternatives or none", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 123.
+ *
+ * <p>
+ * rule alt label <em>label</em> redefined in rule <em>rule1</em>,
+ * originally in rule <em>rule2</em></p>
+ */
+ ALT_LABEL_REDEF(123, "rule alt label <arg> redefined in rule <arg2>, originally in rule <arg3>", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 124.
+ *
+ * <p>
+ * rule alt label <em>label</em> conflicts with rule <em>rule</em></p>
+ */
+ ALT_LABEL_CONFLICTS_WITH_RULE(124, "rule alt label <arg> conflicts with rule <arg2>", ErrorSeverity.ERROR),
+ /**
+ * Compiler Warning 125.
+ *
+ * <p>implicit definition of token <em>Token</em> in parser</p>
+ */
+ IMPLICIT_TOKEN_DEFINITION(125, "implicit definition of token <arg> in parser", ErrorSeverity.WARNING),
+ /**
+ * Compiler Error 126.
+ *
+ * <p>
+ * cannot create implicit token for string literal in non-combined grammar:
+ * <em>literal</em></p>
+ */
+ IMPLICIT_STRING_DEFINITION(126, "cannot create implicit token for string literal in non-combined grammar: <arg>", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 128.
+ *
+ * <p>
+ * attribute references not allowed in lexer actions:
+ * <em>expression</em></p>
+ */
+ ATTRIBUTE_IN_LEXER_ACTION(128, "attribute references not allowed in lexer actions: $<arg>", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 130.
+ *
+ * <p>label <em>label</em> assigned to a block which is not a set</p>
+ */
+ LABEL_BLOCK_NOT_A_SET(130, "label <arg> assigned to a block which is not a set", ErrorSeverity.ERROR),
+ /**
+ * Compiler Warning 131.
+ *
+ * <p>This warning may take any of the following forms.</p>
+ *
+ * <ul>
+ * <li>greedy block {@code ()*} contains wildcard; the non-greedy syntax {@code ()*?} may be preferred</li>
+ * <li>greedy block {@code ()+} contains wildcard; the non-greedy syntax {@code ()+?} may be preferred</li>
+ * </ul>
+ */
+ EXPECTED_NON_GREEDY_WILDCARD_BLOCK(131, "greedy block ()<arg> contains wildcard; the non-greedy syntax ()<arg>? may be preferred", ErrorSeverity.WARNING),
+ /**
+ * Compiler Error 132.
+ *
+ * <p>
+ * action in lexer rule <em>rule</em> must be last element of single
+ * outermost alt</p>
+ *
+ * @deprecated This error is no longer issued by ANTLR 4.2.
+ */
+ @Deprecated
+ LEXER_ACTION_PLACEMENT_ISSUE(132, "action in lexer rule <arg> must be last element of single outermost alt", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 133.
+ *
+ * <p>
+ * {@code ->command} in lexer rule <em>rule</em> must be last element of
+ * single outermost alt</p>
+ */
+ LEXER_COMMAND_PLACEMENT_ISSUE(133, "->command in lexer rule <arg> must be last element of single outermost alt", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 134.
+ *
+ * <p>
+ * symbol <em>symbol</em> conflicts with generated code in target language
+ * or runtime</p>
+ *
+ * <p>
+ * Note: This error has the same number as the unrelated error
+ * {@link #UNSUPPORTED_REFERENCE_IN_LEXER_SET}.</p>
+ */
+ USE_OF_BAD_WORD(134, "symbol <arg> conflicts with generated code in target language or runtime", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 134.
+ *
+ * <p>rule reference <em>rule</em> is not currently supported in a set</p>
+ *
+ * <p>
+ * Note: This error has the same number as the unrelated error
+ * {@link #USE_OF_BAD_WORD}.</p>
+ */
+ UNSUPPORTED_REFERENCE_IN_LEXER_SET(134, "rule reference <arg> is not currently supported in a set", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 135.
+ *
+ * <p>cannot assign a value to list label <em>label</em></p>
+ */
+ ASSIGNMENT_TO_LIST_LABEL(135, "cannot assign a value to list label <arg>", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 136.
+ *
+ * <p>return value <em>name</em> conflicts with rule with same name</p>
+ */
+ RETVAL_CONFLICTS_WITH_RULE(136, "return value <arg> conflicts with rule with same name", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 137.
+ *
+ * <p>return value <em>name</em> conflicts with token with same name</p>
+ */
+ RETVAL_CONFLICTS_WITH_TOKEN(137, "return value <arg> conflicts with token with same name", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 138.
+ *
+ * <p>parameter <em>parameter</em> conflicts with rule with same name</p>
+ */
+ ARG_CONFLICTS_WITH_RULE(138, "parameter <arg> conflicts with rule with same name", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 139.
+ *
+ * <p>parameter <em>parameter</em> conflicts with token with same name</p>
+ */
+ ARG_CONFLICTS_WITH_TOKEN(139, "parameter <arg> conflicts with token with same name", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 140.
+ *
+ * <p>local <em>local</em> conflicts with rule with same name</p>
+ */
+ LOCAL_CONFLICTS_WITH_RULE(140, "local <arg> conflicts with rule with same name", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 141.
+ *
+ * <p>local <em>local</em> conflicts with rule token same name</p>
+ */
+ LOCAL_CONFLICTS_WITH_TOKEN(141, "local <arg> conflicts with rule token same name", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 142.
+ *
+ * <p>local <em>local</em> conflicts with parameter with same name</p>
+ */
+ LOCAL_CONFLICTS_WITH_ARG(142, "local <arg> conflicts with parameter with same name", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 143.
+ *
+ * <p>local <em>local</em> conflicts with return value with same name</p>
+ */
+ LOCAL_CONFLICTS_WITH_RETVAL(143, "local <arg> conflicts with return value with same name", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 144.
+ *
+ * <p>
+ * multi-character literals are not allowed in lexer sets:
+ * <em>literal</em></p>
+ */
+ INVALID_LITERAL_IN_LEXER_SET(144, "multi-character literals are not allowed in lexer sets: <arg>", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 145.
+ *
+ * <p>
+ * lexer mode <em>mode</em> must contain at least one non-fragment
+ * rule</p>
+ *
+ * <p>
+ * Every lexer mode must contain at least one rule which is not declared
+ * with the {@code fragment} modifier.</p>
+ */
+ MODE_WITHOUT_RULES(145, "lexer mode <arg> must contain at least one non-fragment rule", ErrorSeverity.ERROR),
+ /**
+ * Compiler Warning 146.
+ *
+ * <p>non-fragment lexer rule <em>rule</em> can match the empty string</p>
+ *
+ * <p>All non-fragment lexer rules must match at least one character.</p>
+ *
+ * <p>The following example shows this error.</p>
+ *
+ * <pre>
+ * Whitespace : [ \t]+; // ok
+ * Whitespace : [ \t]; // ok
+ *
+ * fragment WS : [ \t]*; // ok
+ *
+ * Whitespace : [ \t]*; // error 146
+ * </pre>
+ */
+ EPSILON_TOKEN(146, "non-fragment lexer rule <arg> can match the empty string", ErrorSeverity.WARNING),
+ /**
+ * Compiler Error 147.
+ *
+ * <p>
+ * left recursive rule <em>rule</em> must contain an alternative which is
+ * not left recursive</p>
+ *
+ * <p>Left-recursive rules must contain at least one alternative which is not
+ * left recursive.</p>
+ *
+ * <p>The following rule produces this error.</p>
+ *
+ * <pre>
+ * // error 147:
+ * a : a ID
+ * | a INT
+ * ;
+ * </pre>
+ */
+ NO_NON_LR_ALTS(147, "left recursive rule <arg> must contain an alternative which is not left recursive", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 148.
+ *
+ * <p>
+ * left recursive rule <em>rule</em> contains a left recursive alternative
+ * which can be followed by the empty string</p>
+ *
+ * <p>In left-recursive rules, all left-recursive alternatives must match at
+ * least one symbol following the recursive rule invocation.</p>
+ *
+ * <p>The following rule produces this error.</p>
+ *
+ * <pre>
+ * a : ID // ok (alternative is not left recursive)
+ * | a INT // ok (a must be follow by INT)
+ * | a ID? // error 148 (the ID following a is optional)
+ * ;
+ * </pre>
+ */
+ EPSILON_LR_FOLLOW(148, "left recursive rule <arg> contains a left recursive alternative which can be followed by the empty string", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 149.
+ *
+ * <p>
+ * lexer command <em>command</em> does not exist or is not supported by
+ * the current target</p>
+ *
+ * <p>Each lexer command requires an explicit implementation in the target
+ * templates. This error indicates that the command was incorrectly written
+ * or is not supported by the current target.</p>
+ *
+ * <p>The following rule produces this error.</p>
+ *
+ * <pre>
+ * X : 'foo' -> type(Foo); // ok
+ * Y : 'foo' -> token(Foo); // error 149 (token is not a supported lexer command)
+ * </pre>
+ *
+ * @since 4.1
+ */
+ INVALID_LEXER_COMMAND(149, "lexer command <arg> does not exist or is not supported by the current target", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 150.
+ *
+ * <p>missing argument for lexer command <em>command</em></p>
+ *
+ * <p>Some lexer commands require an argument.</p>
+ *
+ * <p>The following rule produces this error.</p>
+ *
+ * <pre>
+ * X : 'foo' -> type(Foo); // ok
+ * Y : 'foo' -> type; // error 150 (the type command requires an argument)
+ * </pre>
+ *
+ * @since 4.1
+ */
+ MISSING_LEXER_COMMAND_ARGUMENT(150, "missing argument for lexer command <arg>", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 151.
+ *
+ * <p>lexer command <em>command</em> does not take any arguments</p>
+ *
+ * <p>A lexer command which does not take parameters was invoked with an
+ * argument.</p>
+ *
+ * <p>The following rule produces this error.</p>
+ *
+ * <pre>
+ * X : 'foo' -> popMode; // ok
+ * Y : 'foo' -> popMode(A); // error 151 (the popMode command does not take an argument)
+ * </pre>
+ *
+ * @since 4.1
+ */
+ UNWANTED_LEXER_COMMAND_ARGUMENT(151, "lexer command <arg> does not take any arguments", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 152.
+ *
+ * <p>unterminated string literal</p>
+ *
+ * <p>The grammar contains an unterminated string literal.</p>
+ *
+ * <p>The following rule produces this error.</p>
+ *
+ * <pre>
+ * x : 'x'; // ok
+ * y : 'y'; // error 152
+ * </pre>
+ *
+ * @since 4.1
+ */
+ UNTERMINATED_STRING_LITERAL(152, "unterminated string literal", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 153.
+ *
+ * <p>
+ * rule <em>rule</em> contains a closure with at least one alternative
+ * that can match an empty string</p>
+ *
+ * <p>A rule contains a closure ({@code (...)*}) or positive closure
+ * ({@code (...)+}) around an empty alternative.</p>
+ *
+ * <p>The following rule produces this error.</p>
+ *
+ * <pre>
+ * x : ;
+ * y : x+; // error 153
+ * z1 : ('foo' | 'bar'? 'bar2'?)*; // error 153
+ * z2 : ('foo' | 'bar' 'bar2'? | 'bar2')*; // ok
+ * </pre>
+ *
+ * @since 4.1
+ */
+ EPSILON_CLOSURE(153, "rule <arg> contains a closure with at least one alternative that can match an empty string", ErrorSeverity.ERROR),
+ /**
+ * Compiler Warning 154.
+ *
+ * <p>
+ * rule <em>rule</em> contains an optional block with at least one
+ * alternative that can match an empty string</p>
+ *
+ * <p>A rule contains an optional block ({@code (...)?}) around an empty
+ * alternative.</p>
+ *
+ * <p>The following rule produces this warning.</p>
+ *
+ * <pre>
+ * x : ;
+ * y : x?; // warning 154
+ * z1 : ('foo' | 'bar'? 'bar2'?)?; // warning 154
+ * z2 : ('foo' | 'bar' 'bar2'? | 'bar2')?; // ok
+ * </pre>
+ *
+ * @since 4.1
+ */
+ EPSILON_OPTIONAL(154, "rule <arg> contains an optional block with at least one alternative that can match an empty string", ErrorSeverity.WARNING),
+ /**
+ * Compiler Warning 155.
+ *
+ * <p>
+ * rule <em>rule</em> contains a lexer command with an unrecognized
+ * constant value; lexer interpreters may produce incorrect output</p>
+ *
+ * <p>A lexer rule contains a standard lexer command, but the constant value
+ * argument for the command is an unrecognized string. As a result, the
+ * lexer command will be translated as a custom lexer action, preventing the
+ * command from executing in some interpreted modes. The output of the lexer
+ * interpreter may not match the output of the generated lexer.</p>
+ *
+ * <p>The following rule produces this warning.</p>
+ *
+ * <pre>
+ * &#064;members {
+ * public static final int CUSTOM = HIDDEN + 1;
+ * }
+ *
+ * X : 'foo' -> channel(HIDDEN); // ok
+ * Y : 'bar' -> channel(CUSTOM); // warning 155
+ * </pre>
+ *
+ * @since 4.2
+ */
+ UNKNOWN_LEXER_CONSTANT(155, "rule <arg> contains a lexer command with an unrecognized constant value; lexer interpreters may produce incorrect output", ErrorSeverity.WARNING),
+ /**
+ * Compiler Error 156.
+ *
+ * <p>invalid escape sequence</p>
+ *
+ * <p>The grammar contains a string literal with an invalid escape sequence.</p>
+ *
+ * <p>The following rule produces this error.</p>
+ *
+ * <pre>
+ * x : 'x'; // ok
+ * y : '\u005Cu'; // error 156
+ * </pre>
+ *
+ * @since 4.2.1
+ */
+ INVALID_ESCAPE_SEQUENCE(156, "invalid escape sequence", ErrorSeverity.ERROR),
+ /**
+ * Compiler Warning 157.
+ *
+ * <p>rule <em>rule</em> contains an assoc element option in an
+ * unrecognized location</p>
+ *
+ * <p>
+ * In ANTLR 4.2, the position of the {@code assoc} element option was moved
+ * from the operator terminal(s) to the alternative itself. This warning is
+ * reported when an {@code assoc} element option is specified on a grammar
+ * element that is not recognized by the current version of ANTLR, and as a
+ * result will simply be ignored.
+ * </p>
+ *
+ * <p>The following rule produces this warning.</p>
+ *
+ * <pre>
+ * x : 'x'
+ * | x '+'&lt;assoc=right&gt; x // warning 157
+ * |&lt;assoc=right&gt; x * x // ok
+ * ;
+ * </pre>
+ *
+ * @since 4.2.1
+ */
+ UNRECOGNIZED_ASSOC_OPTION(157, "rule <arg> contains an assoc terminal option in an unrecognized location", ErrorSeverity.WARNING),
+ /**
+ * Compiler Warning 158.
+ *
+ * <p>fragment rule <em>rule</em> contains an action or command which can
+ * never be executed</p>
+ *
+ * <p>A lexer rule which is marked with the {@code fragment} modifier
+ * contains an embedded action or lexer command. ANTLR lexers only execute
+ * commands and embedded actions located in the top-level matched rule.
+ * Since fragment rules can never be the top-level rule matched by a lexer,
+ * actions or commands placed in these rules can never be executed during
+ * the lexing process.</p>
+ *
+ * <p>The following rule produces this warning.</p>
+ *
+ * <pre>
+ * X1 : 'x' -> more // ok
+ * ;
+ * Y1 : 'x' {more();} // ok
+ * ;
+ * fragment
+ * X2 : 'x' -> more // warning 158
+ * ;
+ * fragment
+ * Y2 : 'x' {more();} // warning 158
+ * ;
+ * </pre>
+ *
+ * @since 4.2.1
+ */
+ FRAGMENT_ACTION_IGNORED(158, "fragment rule <arg> contains an action or command which can never be executed", ErrorSeverity.WARNING),
+ /**
+ * Compiler Error 159.
+ *
+ * <p>cannot declare a rule with reserved name <em>rule</em></p>
+ *
+ * <p>A rule was declared with a reserved name.</p>
+ *
+ * <p>The following rule produces this error.</p>
+ *
+ * <pre>
+ * EOF : ' ' // error 159 (EOF is a reserved name)
+ * ;
+ * </pre>
+ *
+ * @since 4.2.1
+ */
+ RESERVED_RULE_NAME(159, "cannot declare a rule with reserved name <arg>", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 160.
+ *
+ * <p>reference to parser rule <em>rule</em> in lexer rule <em>name</em></p>
+ *
+ * @see #UNDEFINED_RULE_REF
+ */
+ PARSER_RULE_REF_IN_LEXER_RULE(160, "reference to parser rule <arg> in lexer rule <arg2>", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 161.
+ *
+ * <p>channel <em>name</em> conflicts with token with same name</p>
+ */
+ CHANNEL_CONFLICTS_WITH_TOKEN(161, "channel <arg> conflicts with token with same name", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 162.
+ *
+ * <p>channel <em>name</em> conflicts with mode with same name</p>
+ */
+ CHANNEL_CONFLICTS_WITH_MODE(162, "channel <arg> conflicts with mode with same name", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 163.
+ *
+ * <p>custom channels are not supported in parser grammars</p>
+ */
+ CHANNELS_BLOCK_IN_PARSER_GRAMMAR(163, "custom channels are not supported in parser grammars", ErrorSeverity.ERROR),
+ /**
+ * Compiler Error 164.
+ *
+ * <p>custom channels are not supported in combined grammars</p>
+ */
+ CHANNELS_BLOCK_IN_COMBINED_GRAMMAR(164, "custom channels are not supported in combined grammars", ErrorSeverity.ERROR),
+
+ NONCONFORMING_LR_RULE(169, "rule <arg> is left recursive but doesn't conform to a pattern ANTLR can handle", ErrorSeverity.ERROR),
+
+ /*
+ * Backward incompatibility errors
+ */
+
+ /**
+ * Compiler Error 200.
+ *
+ * <p>tree grammars are not supported in ANTLR 4</p>
+ *
+ * <p>
+ * This error message is provided as a compatibility notice for users
+ * migrating from ANTLR 3. ANTLR 4 does not support tree grammars, but
+ * instead offers automatically generated parse tree listeners and visitors
+ * as a more maintainable alternative.</p>
+ */
+ V3_TREE_GRAMMAR(200, "tree grammars are not supported in ANTLR 4", ErrorSeverity.ERROR),
+ /**
+ * Compiler Warning 201.
+ *
+ * <p>
+ * labels in lexer rules are not supported in ANTLR 4; actions cannot
+ * reference elements of lexical rules but you can use
+ * {@link Lexer#getText()} to get the entire text matched for the rule</p>
+ *
+ * <p>
+ * ANTLR 4 uses a DFA for recognition of entire tokens, resulting in faster
+ * and smaller lexers than ANTLR 3 produced. As a result, sub-rules
+ * referenced within lexer rules are not tracked independently, and cannot
+ * be assigned to labels.</p>
+ */
+ V3_LEXER_LABEL(201, "labels in lexer rules are not supported in ANTLR 4; " +
+ "actions cannot reference elements of lexical rules but you can use " +
+ "getText() to get the entire text matched for the rule", ErrorSeverity.WARNING),
+ /**
+ * Compiler Warning 202.
+ *
+ * <p>
+ * {@code tokens {A; B;}} syntax is now {@code tokens {A, B}} in ANTLR
+ * 4</p>
+ *
+ * <p>
+ * ANTLR 4 uses comma-separated token declarations in the {@code tokens{}}
+ * block. This warning appears when the tokens block is written using the
+ * ANTLR 3 syntax of semicolon-terminated token declarations.</p>
+ *
+ * <p>
+ * <strong>NOTE:</strong> ANTLR 4 does not allow a trailing comma to appear following the
+ * last token declared in the {@code tokens{}} block.</p>
+ */
+ V3_TOKENS_SYNTAX(202, "tokens {A; B;} syntax is now tokens {A, B} in ANTLR 4", ErrorSeverity.WARNING),
+ /**
+ * Compiler Error 203.
+ *
+ * <p>
+ * assignments in {@code tokens{}} are not supported in ANTLR 4; use lexical
+ * rule <em>TokenName</em> : <em>LiteralValue</em>; instead</p>
+ *
+ * <p>
+ * ANTLR 3 allowed literal tokens to be declared and assigned a value within
+ * the {@code tokens{}} block. ANTLR 4 no longer offers this syntax. When
+ * migrating a grammar from ANTLR 3 to ANTLR 4, any tokens with a literal
+ * value declared in the {@code tokens{}} block should be converted to
+ * standard lexer rules.</p>
+ */
+ V3_ASSIGN_IN_TOKENS(203, "assignments in tokens{} are not supported in ANTLR 4; use lexical rule <arg> : <arg2>; instead", ErrorSeverity.ERROR),
+ /**
+ * Compiler Warning 204.
+ *
+ * <p>
+ * {@code {...}?=>} explicitly gated semantic predicates are deprecated in
+ * ANTLR 4; use {@code {...}?} instead</p>
+ *
+ * <p>
+ * ANTLR 4 treats semantic predicates consistently in a manner similar to
+ * gated semantic predicates in ANTLR 3. When migrating a grammar from ANTLR
+ * 3 to ANTLR 4, all uses of the gated semantic predicate syntax can be
+ * safely converted to the standard semantic predicated syntax, which is the
+ * only form used by ANTLR 4.</p>
+ */
+ V3_GATED_SEMPRED(204, "{...}?=> explicitly gated semantic predicates are deprecated in ANTLR 4; use {...}? instead", ErrorSeverity.WARNING),
+ /**
+ * Compiler Error 205.
+ *
+ * <p>{@code (...)=>} syntactic predicates are not supported in ANTLR 4</p>
+ *
+ * <p>
+ * ANTLR 4's improved lookahead algorithms do not require the use of
+ * syntactic predicates to disambiguate long lookahead sequences. The
+ * syntactic predicates should be removed when migrating a grammar from
+ * ANTLR 3 to ANTLR 4.</p>
+ */
+ V3_SYNPRED(205, "(...)=> syntactic predicates are not supported in ANTLR 4", ErrorSeverity.ERROR),
+
+ // Dependency sorting errors
+
+ /** t1.g4 -> t2.g4 -> t3.g4 ->t1.g4 */
+ //CIRCULAR_DEPENDENCY(200, "your grammars contain a circular dependency and cannot be sorted into a valid build order", ErrorSeverity.ERROR),
+ ;
+
+ /**
+ * The error or warning message, in StringTemplate 4 format using {@code <}
+ * and {@code >} as the delimiters. Arguments for the message may be
+ * referenced using the following names:
+ *
+ * <ul>
+ * <li>{@code arg}: The first template argument</li>
+ * <li>{@code arg2}: The second template argument</li>
+ * <li>{@code arg3}: The third template argument</li>
+ * <li>{@code verbose}: {@code true} if verbose messages were requested; otherwise, {@code false}</li>
+ * <li>{@code exception}: The exception which resulted in the error, if any.</li>
+ * <li>{@code stackTrace}: The stack trace for the exception, when available.</li>
+ * </ul>
+ */
+ public final String msg;
+ /**
+ * The error or warning number.
+ *
+ * <p>The code should be unique, and following its
+ * use in a release should not be altered or reassigned.</p>
+ */
+ public final int code;
+ /**
+ * The error severity.
+ */
+ public final ErrorSeverity severity;
+
+ /**
+ * Constructs a new {@link ErrorType} with the specified code, message, and
+ * severity.
+ *
+ * @param code The unique error number.
+ * @param msg The error message template.
+ * @param severity The error severity.
+ */
+ ErrorType(int code, String msg, ErrorSeverity severity) {
+ this.code = code;
+ this.msg = msg;
+ this.severity = severity;
+ }
+}
diff --git a/tool/src/org/antlr/v4/tool/Grammar.java b/tool/src/org/antlr/v4/tool/Grammar.java
new file mode 100644
index 0000000..5632ab4
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/Grammar.java
@@ -0,0 +1,1343 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.tool;
+
+import org.antlr.v4.Tool;
+import org.antlr.v4.analysis.LeftRecursiveRuleTransformer;
+import org.antlr.v4.automata.ParserATNFactory;
+import org.antlr.v4.misc.CharSupport;
+import org.antlr.v4.misc.OrderedHashMap;
+import org.antlr.v4.misc.Utils;
+import org.antlr.v4.parse.ANTLRParser;
+import org.antlr.v4.parse.GrammarASTAdaptor;
+import org.antlr.v4.parse.GrammarTreeVisitor;
+import org.antlr.v4.parse.TokenVocabParser;
+import org.antlr.v4.runtime.CharStream;
+import org.antlr.v4.runtime.Lexer;
+import org.antlr.v4.runtime.LexerInterpreter;
+import org.antlr.v4.runtime.ParserInterpreter;
+import org.antlr.v4.runtime.Token;
+import org.antlr.v4.runtime.TokenStream;
+import org.antlr.v4.runtime.Vocabulary;
+import org.antlr.v4.runtime.VocabularyImpl;
+import org.antlr.v4.runtime.atn.ATN;
+import org.antlr.v4.runtime.atn.ATNDeserializer;
+import org.antlr.v4.runtime.atn.ATNSerializer;
+import org.antlr.v4.runtime.atn.SemanticContext;
+import org.antlr.v4.runtime.dfa.DFA;
+import org.antlr.v4.runtime.misc.IntSet;
+import org.antlr.v4.runtime.misc.Interval;
+import org.antlr.v4.runtime.misc.IntervalSet;
+import org.antlr.v4.runtime.misc.Pair;
+import org.antlr.v4.tool.ast.ActionAST;
+import org.antlr.v4.tool.ast.GrammarAST;
+import org.antlr.v4.tool.ast.GrammarASTWithOptions;
+import org.antlr.v4.tool.ast.GrammarRootAST;
+import org.antlr.v4.tool.ast.PredAST;
+import org.antlr.v4.tool.ast.RuleAST;
+import org.antlr.v4.tool.ast.TerminalAST;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class Grammar implements AttributeResolver {
+ public static final String GRAMMAR_FROM_STRING_NAME = "<string>";
+ /**
+ * This value is used in the following situations to indicate that a token
+ * type does not have an associated name which can be directly referenced in
+ * a grammar.
+ *
+ * <ul>
+ * <li>This value is the name and display name for the token with type
+ * {@link Token#INVALID_TYPE}.</li>
+ * <li>This value is the name for tokens with a type not represented by a
+ * named token. The display name for these tokens is simply the string
+ * representation of the token type as an integer.</li>
+ * </ul>
+ */
+ public static final String INVALID_TOKEN_NAME = "<INVALID>";
+ /**
+ * This value is used as the name for elements in the array returned by
+ * {@link #getRuleNames} for indexes not associated with a rule.
+ */
+ public static final String INVALID_RULE_NAME = "<invalid>";
+
+ public static final Set<String> parserOptions = new HashSet<String>();
+ static {
+ parserOptions.add("superClass");
+ parserOptions.add("TokenLabelType");
+ parserOptions.add("tokenVocab");
+ parserOptions.add("language");
+ }
+
+ public static final Set<String> lexerOptions = parserOptions;
+
+ public static final Set<String> ruleOptions = new HashSet<String>();
+
+ public static final Set<String> ParserBlockOptions = new HashSet<String>();
+
+ public static final Set<String> LexerBlockOptions = new HashSet<String>();
+
+ /** Legal options for rule refs like id<key=value> */
+ public static final Set<String> ruleRefOptions = new HashSet<String>();
+ static {
+ ruleRefOptions.add(LeftRecursiveRuleTransformer.PRECEDENCE_OPTION_NAME);
+ ruleRefOptions.add(LeftRecursiveRuleTransformer.TOKENINDEX_OPTION_NAME);
+ }
+
+ /** Legal options for terminal refs like ID<assoc=right> */
+ public static final Set<String> tokenOptions = new HashSet<String>();
+ static {
+ tokenOptions.add("assoc");
+ tokenOptions.add(LeftRecursiveRuleTransformer.TOKENINDEX_OPTION_NAME);
+ }
+
+ public static final Set<String> actionOptions = new HashSet<String>();
+
+ public static final Set<String> semPredOptions = new HashSet<String>();
+ static {
+ semPredOptions.add(LeftRecursiveRuleTransformer.PRECEDENCE_OPTION_NAME);
+ semPredOptions.add("fail");
+ }
+
+ public static final Set<String> doNotCopyOptionsToLexer = new HashSet<String>();
+ static {
+ doNotCopyOptionsToLexer.add("superClass");
+ doNotCopyOptionsToLexer.add("TokenLabelType");
+ doNotCopyOptionsToLexer.add("tokenVocab");
+ }
+
+ public static final Map<String, AttributeDict> grammarAndLabelRefTypeToScope =
+ new HashMap<String, AttributeDict>();
+ static {
+ grammarAndLabelRefTypeToScope.put("parser:RULE_LABEL", Rule.predefinedRulePropertiesDict);
+ grammarAndLabelRefTypeToScope.put("parser:TOKEN_LABEL", AttributeDict.predefinedTokenDict);
+ grammarAndLabelRefTypeToScope.put("combined:RULE_LABEL", Rule.predefinedRulePropertiesDict);
+ grammarAndLabelRefTypeToScope.put("combined:TOKEN_LABEL", AttributeDict.predefinedTokenDict);
+ }
+
+ public String name;
+ public GrammarRootAST ast;
+
+ /** Track token stream used to create this grammar */
+
+ public final org.antlr.runtime.TokenStream tokenStream;
+
+ /** If we transform grammar, track original unaltered token stream.
+ * This is set to the same value as tokenStream when tokenStream is
+ * initially set.
+ *
+ * If this field differs from tokenStream, then we have transformed
+ * the grammar.
+ */
+
+ public org.antlr.runtime.TokenStream originalTokenStream;
+
+ public String text; // testing only
+ public String fileName;
+
+ /** Was this parser grammar created from a COMBINED grammar? If so,
+ * this is what we extracted.
+ */
+ public LexerGrammar implicitLexer;
+
+ /** If this is an extracted/implicit lexer, we point at original grammar */
+ public Grammar originalGrammar;
+
+ /** If we're imported, who imported us? If null, implies grammar is root */
+ public Grammar parent;
+ public List<Grammar> importedGrammars;
+
+ /** All rules defined in this specific grammar, not imported. Also does
+ * not include lexical rules if combined.
+ */
+ public OrderedHashMap<String, Rule> rules = new OrderedHashMap<String, Rule>();
+ public List<Rule> indexToRule = new ArrayList<Rule>();
+
+ int ruleNumber = 0; // used to get rule indexes (0..n-1)
+ int stringLiteralRuleNumber = 0; // used to invent rule names for 'keyword', ';', ... (0..n-1)
+
+ /** The ATN that represents the grammar with edges labelled with tokens
+ * or epsilon. It is more suitable to analysis than an AST representation.
+ */
+ public ATN atn;
+
+ public Map<Integer, Interval> stateToGrammarRegionMap;
+
+ public Map<Integer, DFA> decisionDFAs = new HashMap<Integer, DFA>();
+
+ public List<IntervalSet[]> decisionLOOK;
+
+ public final Tool tool;
+
+ /** Token names and literal tokens like "void" are uniquely indexed.
+ * with -1 implying EOF. Characters are different; they go from
+ * -1 (EOF) to \uFFFE. For example, 0 could be a binary byte you
+ * want to lexer. Labels of DFA/ATN transitions can be both tokens
+ * and characters. I use negative numbers for bookkeeping labels
+ * like EPSILON. Char/String literals and token types overlap in the same
+ * space, however.
+ */
+ int maxTokenType = Token.MIN_USER_TOKEN_TYPE -1;
+
+ /**
+ * Map token like {@code ID} (but not literals like {@code 'while'}) to its
+ * token type.
+ */
+ public final Map<String, Integer> tokenNameToTypeMap = new LinkedHashMap<String, Integer>();
+
+ /**
+ * Map token literals like {@code 'while'} to its token type. It may be that
+ * {@code WHILE="while"=35}, in which case both {@link #tokenNameToTypeMap}
+ * and this field will have entries both mapped to 35.
+ */
+ public final Map<String, Integer> stringLiteralToTypeMap = new LinkedHashMap<String, Integer>();
+
+ /**
+ * Reverse index for {@link #stringLiteralToTypeMap}. Indexed with raw token
+ * type. 0 is invalid.
+ */
+ public final List<String> typeToStringLiteralList = new ArrayList<String>();
+
+ /**
+ * Map a token type to its token name. Indexed with raw token type. 0 is
+ * invalid.
+ */
+ public final List<String> typeToTokenList = new ArrayList<String>();
+
+ /**
+ * The maximum channel value which is assigned by this grammar. Values below
+ * {@link Token#MIN_USER_CHANNEL_VALUE} are assumed to be predefined.
+ */
+ int maxChannelType = Token.MIN_USER_CHANNEL_VALUE - 1;
+
+ /**
+ * Map channel like {@code COMMENTS_CHANNEL} to its constant channel value.
+ * Only user-defined channels are defined in this map.
+ */
+ public final Map<String, Integer> channelNameToValueMap = new LinkedHashMap<String, Integer>();
+
+ /**
+ * Map a constant channel value to its name. Indexed with raw channel value.
+ * The predefined channels {@link Token#DEFAULT_CHANNEL} and
+ * {@link Token#HIDDEN_CHANNEL} are not stored in this list, so the values
+ * at the corresponding indexes is {@code null}.
+ */
+ public final List<String> channelValueToNameList = new ArrayList<String>();
+
+ /** Map a name to an action.
+ * The code generator will use this to fill holes in the output files.
+ * I track the AST node for the action in case I need the line number
+ * for errors.
+ */
+ public Map<String,ActionAST> namedActions = new HashMap<String,ActionAST>();
+
+ /** Tracks all user lexer actions in all alternatives of all rules.
+ * Doesn't track sempreds. maps tree node to action index (alt number 1..n).
+ */
+ public LinkedHashMap<ActionAST, Integer> lexerActions = new LinkedHashMap<ActionAST, Integer>();
+
+ /** All sempreds found in grammar; maps tree node to sempred index;
+ * sempred index is 0..n-1
+ */
+ public LinkedHashMap<PredAST, Integer> sempreds = new LinkedHashMap<PredAST, Integer>();
+ /** Map the other direction upon demand */
+ public LinkedHashMap<Integer, PredAST> indexToPredMap;
+
+ public static final String AUTO_GENERATED_TOKEN_NAME_PREFIX = "T__";
+
+ public Grammar(Tool tool, GrammarRootAST ast) {
+ if ( ast==null ) {
+ throw new NullPointerException("ast");
+ }
+
+ if (ast.tokenStream == null) {
+ throw new IllegalArgumentException("ast must have a token stream");
+ }
+
+ this.tool = tool;
+ this.ast = ast;
+ this.name = (ast.getChild(0)).getText();
+ this.tokenStream = ast.tokenStream;
+ this.originalTokenStream = this.tokenStream;
+
+ initTokenSymbolTables();
+ }
+
+ /** For testing */
+ public Grammar(String grammarText) throws org.antlr.runtime.RecognitionException {
+ this(GRAMMAR_FROM_STRING_NAME, grammarText, null);
+ }
+
+ public Grammar(String grammarText, LexerGrammar tokenVocabSource) throws org.antlr.runtime.RecognitionException {
+ this(GRAMMAR_FROM_STRING_NAME, grammarText, tokenVocabSource, null);
+ }
+
+ /** For testing */
+ public Grammar(String grammarText, ANTLRToolListener listener)
+ throws org.antlr.runtime.RecognitionException
+ {
+ this(GRAMMAR_FROM_STRING_NAME, grammarText, listener);
+ }
+
+ /** For testing; builds trees, does sem anal */
+ public Grammar(String fileName, String grammarText)
+ throws org.antlr.runtime.RecognitionException
+ {
+ this(fileName, grammarText, null);
+ }
+
+ /** For testing; builds trees, does sem anal */
+ public Grammar(String fileName, String grammarText, ANTLRToolListener listener)
+ throws org.antlr.runtime.RecognitionException
+ {
+ this(fileName, grammarText, null, listener);
+ }
+
+ /** For testing; builds trees, does sem anal */
+ public Grammar(String fileName, String grammarText, Grammar tokenVocabSource, ANTLRToolListener listener)
+ throws org.antlr.runtime.RecognitionException
+ {
+ this.text = grammarText;
+ this.fileName = fileName;
+ this.tool = new Tool();
+ this.tool.addListener(listener);
+ org.antlr.runtime.ANTLRStringStream in = new org.antlr.runtime.ANTLRStringStream(grammarText);
+ in.name = fileName;
+
+ this.ast = tool.parse(fileName, in);
+ if ( ast==null ) {
+ throw new UnsupportedOperationException();
+ }
+
+ if (ast.tokenStream == null) {
+ throw new IllegalStateException("expected ast to have a token stream");
+ }
+
+ this.tokenStream = ast.tokenStream;
+ this.originalTokenStream = this.tokenStream;
+
+ // ensure each node has pointer to surrounding grammar
+ final Grammar thiz = this;
+ org.antlr.runtime.tree.TreeVisitor v = new org.antlr.runtime.tree.TreeVisitor(new GrammarASTAdaptor());
+ v.visit(ast, new org.antlr.runtime.tree.TreeVisitorAction() {
+ @Override
+ public Object pre(Object t) { ((GrammarAST)t).g = thiz; return t; }
+ @Override
+ public Object post(Object t) { return t; }
+ });
+ initTokenSymbolTables();
+
+ if (tokenVocabSource != null) {
+ importVocab(tokenVocabSource);
+ }
+
+ tool.process(this, false);
+ }
+
+ protected void initTokenSymbolTables() {
+ tokenNameToTypeMap.put("EOF", Token.EOF);
+
+ // reserve a spot for the INVALID token
+ typeToTokenList.add(null);
+ }
+
+ public void loadImportedGrammars() {
+ if ( ast==null ) return;
+ GrammarAST i = (GrammarAST)ast.getFirstChildWithType(ANTLRParser.IMPORT);
+ if ( i==null ) return;
+ importedGrammars = new ArrayList<Grammar>();
+ for (Object c : i.getChildren()) {
+ GrammarAST t = (GrammarAST)c;
+ String importedGrammarName = null;
+ if ( t.getType()==ANTLRParser.ASSIGN ) {
+ t = (GrammarAST)t.getChild(1);
+ importedGrammarName = t.getText();
+ }
+ else if ( t.getType()==ANTLRParser.ID ) {
+ importedGrammarName = t.getText();
+ }
+ Grammar g;
+ try {
+ g = tool.loadImportedGrammar(this, t);
+ }
+ catch (IOException ioe) {
+ tool.errMgr.grammarError(ErrorType.ERROR_READING_IMPORTED_GRAMMAR,
+ importedGrammarName,
+ t.getToken(),
+ importedGrammarName,
+ name);
+ continue;
+ }
+ // did it come back as error node or missing?
+ if ( g == null ) continue;
+ g.parent = this;
+ importedGrammars.add(g);
+ g.loadImportedGrammars(); // recursively pursue any imports in this import
+ }
+ }
+
+ public void defineAction(GrammarAST atAST) {
+ if ( atAST.getChildCount()==2 ) {
+ String name = atAST.getChild(0).getText();
+ namedActions.put(name, (ActionAST)atAST.getChild(1));
+ }
+ else {
+ String scope = atAST.getChild(0).getText();
+ String gtype = getTypeString();
+ if ( scope.equals(gtype) || (scope.equals("parser")&&gtype.equals("combined")) ) {
+ String name = atAST.getChild(1).getText();
+ namedActions.put(name, (ActionAST)atAST.getChild(2));
+ }
+ }
+ }
+
+ /**
+ * Define the specified rule in the grammar. This method assigns the rule's
+ * {@link Rule#index} according to the {@link #ruleNumber} field, and adds
+ * the {@link Rule} instance to {@link #rules} and {@link #indexToRule}.
+ *
+ * @param r The rule to define in the grammar.
+ * @return {@code true} if the rule was added to the {@link Grammar}
+ * instance; otherwise, {@code false} if a rule with this name already
+ * existed in the grammar instance.
+ */
+ public boolean defineRule(Rule r) {
+ if ( rules.get(r.name)!=null ) {
+ return false;
+ }
+
+ rules.put(r.name, r);
+ r.index = ruleNumber++;
+ indexToRule.add(r);
+ return true;
+ }
+
+ /**
+ * Undefine the specified rule from this {@link Grammar} instance. The
+ * instance {@code r} is removed from {@link #rules} and
+ * {@link #indexToRule}. This method updates the {@link Rule#index} field
+ * for all rules defined after {@code r}, and decrements {@link #ruleNumber}
+ * in preparation for adding new rules.
+ * <p>
+ * This method does nothing if the current {@link Grammar} does not contain
+ * the instance {@code r} at index {@code r.index} in {@link #indexToRule}.
+ * </p>
+ *
+ * @param r
+ * @return {@code true} if the rule was removed from the {@link Grammar}
+ * instance; otherwise, {@code false} if the specified rule was not defined
+ * in the grammar.
+ */
+ public boolean undefineRule(Rule r) {
+ if (r.index < 0 || r.index >= indexToRule.size() || indexToRule.get(r.index) != r) {
+ return false;
+ }
+
+ assert rules.get(r.name) == r;
+
+ rules.remove(r.name);
+ indexToRule.remove(r.index);
+ for (int i = r.index; i < indexToRule.size(); i++) {
+ assert indexToRule.get(i).index == i + 1;
+ indexToRule.get(i).index--;
+ }
+
+ ruleNumber--;
+ return true;
+ }
+
+// public int getNumRules() {
+// int n = rules.size();
+// List<Grammar> imports = getAllImportedGrammars();
+// if ( imports!=null ) {
+// for (Grammar g : imports) n += g.getNumRules();
+// }
+// return n;
+// }
+
+ public Rule getRule(String name) {
+ Rule r = rules.get(name);
+ if ( r!=null ) return r;
+ return null;
+ /*
+ List<Grammar> imports = getAllImportedGrammars();
+ if ( imports==null ) return null;
+ for (Grammar g : imports) {
+ r = g.getRule(name); // recursively walk up hierarchy
+ if ( r!=null ) return r;
+ }
+ return null;
+ */
+ }
+
+ public ATN getATN() {
+ if ( atn==null ) {
+ ParserATNFactory factory = new ParserATNFactory(this);
+ atn = factory.createATN();
+ }
+ return atn;
+ }
+
+ public Rule getRule(int index) { return indexToRule.get(index); }
+
+ public Rule getRule(String grammarName, String ruleName) {
+ if ( grammarName!=null ) { // scope override
+ Grammar g = getImportedGrammar(grammarName);
+ if ( g ==null ) {
+ return null;
+ }
+ return g.rules.get(ruleName);
+ }
+ return getRule(ruleName);
+ }
+
+ /** Get list of all imports from all grammars in the delegate subtree of g.
+ * The grammars are in import tree preorder. Don't include ourselves
+ * in list as we're not a delegate of ourselves.
+ */
+ public List<Grammar> getAllImportedGrammars() {
+ if (importedGrammars == null) {
+ return null;
+ }
+
+ LinkedHashMap<String, Grammar> delegates = new LinkedHashMap<String, Grammar>();
+ for (Grammar d : importedGrammars) {
+ delegates.put(d.fileName, d);
+ List<Grammar> ds = d.getAllImportedGrammars();
+ if (ds != null) {
+ for (Grammar imported : ds) {
+ delegates.put(imported.fileName, imported);
+ }
+ }
+ }
+
+ return new ArrayList<Grammar>(delegates.values());
+ }
+
+ public List<Grammar> getImportedGrammars() { return importedGrammars; }
+
+ /** Get delegates below direct delegates of g
+ public List<Grammar> getIndirectDelegates(Grammar g) {
+ List<Grammar> direct = getDirectDelegates(g);
+ List<Grammar> delegates = getDelegates(g);
+ delegates.removeAll(direct);
+ return delegates;
+ }
+*/
+
+ public LexerGrammar getImplicitLexer() {
+ return implicitLexer;
+ }
+
+ /** convenience method for Tool.loadGrammar() */
+ public static Grammar load(String fileName) {
+ Tool antlr = new Tool();
+ return antlr.loadGrammar(fileName);
+ }
+
+ /** Return list of imported grammars from root down to our parent.
+ * Order is [root, ..., this.parent]. (us not included).
+ */
+ public List<Grammar> getGrammarAncestors() {
+ Grammar root = getOutermostGrammar();
+ if ( this==root ) return null;
+ List<Grammar> grammars = new ArrayList<Grammar>();
+ // walk backwards to root, collecting grammars
+ Grammar p = this.parent;
+ while ( p!=null ) {
+ grammars.add(0, p); // add to head so in order later
+ p = p.parent;
+ }
+ return grammars;
+ }
+
+ /** Return the grammar that imported us and our parents. Return this
+ * if we're root.
+ */
+ public Grammar getOutermostGrammar() {
+ if ( parent==null ) return this;
+ return parent.getOutermostGrammar();
+ }
+
+ /** Get the name of the generated recognizer; may or may not be same
+ * as grammar name.
+ * Recognizer is TParser and TLexer from T if combined, else
+ * just use T regardless of grammar type.
+ */
+ public String getRecognizerName() {
+ String suffix = "";
+ List<Grammar> grammarsFromRootToMe = getOutermostGrammar().getGrammarAncestors();
+ String qualifiedName = name;
+ if ( grammarsFromRootToMe!=null ) {
+ StringBuilder buf = new StringBuilder();
+ for (Grammar g : grammarsFromRootToMe) {
+ buf.append(g.name);
+ buf.append('_');
+ }
+ buf.append(name);
+ qualifiedName = buf.toString();
+ }
+
+ if ( isCombined() || (isLexer() && implicitLexer!=null) )
+ {
+ suffix = Grammar.getGrammarTypeToFileNameSuffix(getType());
+ }
+ return qualifiedName+suffix;
+ }
+
+ public String getStringLiteralLexerRuleName(String lit) {
+ return AUTO_GENERATED_TOKEN_NAME_PREFIX + stringLiteralRuleNumber++;
+ }
+
+ /** Return grammar directly imported by this grammar */
+ public Grammar getImportedGrammar(String name) {
+ for (Grammar g : importedGrammars) {
+ if ( g.name.equals(name) ) return g;
+ }
+ return null;
+ }
+
+ public int getTokenType(String token) {
+ Integer I;
+ if ( token.charAt(0)=='\'') {
+ I = stringLiteralToTypeMap.get(token);
+ }
+ else { // must be a label like ID
+ I = tokenNameToTypeMap.get(token);
+ }
+ int i = (I!=null)? I : Token.INVALID_TYPE;
+ //tool.log("grammar", "grammar type "+type+" "+tokenName+"->"+i);
+ return i;
+ }
+
+ /** Given a token type, get a meaningful name for it such as the ID
+ * or string literal. If this is a lexer and the ttype is in the
+ * char vocabulary, compute an ANTLR-valid (possibly escaped) char literal.
+ */
+ public String getTokenDisplayName(int ttype) {
+ // inside any target's char range and is lexer grammar?
+ if ( isLexer() &&
+ ttype >= Lexer.MIN_CHAR_VALUE && ttype <= Lexer.MAX_CHAR_VALUE )
+ {
+ return CharSupport.getANTLRCharLiteralForChar(ttype);
+ }
+
+ if ( ttype==Token.EOF ) {
+ return "EOF";
+ }
+
+ if ( ttype==Token.INVALID_TYPE ) {
+ return INVALID_TOKEN_NAME;
+ }
+
+ if (ttype >= 0 && ttype < typeToStringLiteralList.size() && typeToStringLiteralList.get(ttype) != null) {
+ return typeToStringLiteralList.get(ttype);
+ }
+
+ if (ttype >= 0 && ttype < typeToTokenList.size() && typeToTokenList.get(ttype) != null) {
+ return typeToTokenList.get(ttype);
+ }
+
+ return String.valueOf(ttype);
+ }
+
+ /**
+ * Gets the name by which a token can be referenced in the generated code.
+ * For tokens defined in a {@code tokens{}} block or via a lexer rule, this
+ * is the declared name of the token. For token types generated by the use
+ * of a string literal within a parser rule of a combined grammar, this is
+ * the automatically generated token type which includes the
+ * {@link #AUTO_GENERATED_TOKEN_NAME_PREFIX} prefix. For types which are not
+ * associated with a defined token, this method returns
+ * {@link #INVALID_TOKEN_NAME}.
+ *
+ * @param ttype The token type.
+ * @return The name of the token with the specified type.
+ */
+
+ public String getTokenName(int ttype) {
+ // inside any target's char range and is lexer grammar?
+ if ( isLexer() &&
+ ttype >= Lexer.MIN_CHAR_VALUE && ttype <= Lexer.MAX_CHAR_VALUE )
+ {
+ return CharSupport.getANTLRCharLiteralForChar(ttype);
+ }
+
+ if ( ttype==Token.EOF ) {
+ return "EOF";
+ }
+
+ if (ttype >= 0 && ttype < typeToTokenList.size() && typeToTokenList.get(ttype) != null) {
+ return typeToTokenList.get(ttype);
+ }
+
+ return INVALID_TOKEN_NAME;
+ }
+
+ /**
+ * Gets the constant channel value for a user-defined channel.
+ *
+ * <p>
+ * This method only returns channel values for user-defined channels. All
+ * other channels, including the predefined channels
+ * {@link Token#DEFAULT_CHANNEL} and {@link Token#HIDDEN_CHANNEL} along with
+ * any channel defined in code (e.g. in a {@code @members{}} block), are
+ * ignored.</p>
+ *
+ * @param channel The channel name.
+ * @return The channel value, if {@code channel} is the name of a known
+ * user-defined token channel; otherwise, -1.
+ */
+ public int getChannelValue(String channel) {
+ Integer I = channelNameToValueMap.get(channel);
+ int i = (I != null) ? I : -1;
+ return i;
+ }
+
+ /**
+ * Gets an array of rule names for rules defined or imported by the
+ * grammar. The array index is the rule index, and the value is the name of
+ * the rule with the corresponding {@link Rule#index}.
+ *
+ * <p>If no rule is defined with an index for an element of the resulting
+ * array, the value of that element is {@link #INVALID_RULE_NAME}.</p>
+ *
+ * @return The names of all rules defined in the grammar.
+ */
+ public String[] getRuleNames() {
+ String[] result = new String[rules.size()];
+ Arrays.fill(result, INVALID_RULE_NAME);
+ for (Rule rule : rules.values()) {
+ result[rule.index] = rule.name;
+ }
+
+ return result;
+ }
+
+ /**
+ * Gets an array of token names for tokens defined or imported by the
+ * grammar. The array index is the token type, and the value is the result
+ * of {@link #getTokenName} for the corresponding token type.
+ *
+ * @see #getTokenName
+ * @return The token names of all tokens defined in the grammar.
+ */
+ public String[] getTokenNames() {
+ int numTokens = getMaxTokenType();
+ String[] tokenNames = new String[numTokens+1];
+ for (int i = 0; i < tokenNames.length; i++) {
+ tokenNames[i] = getTokenName(i);
+ }
+
+ return tokenNames;
+ }
+
+ /**
+ * Gets an array of display names for tokens defined or imported by the
+ * grammar. The array index is the token type, and the value is the result
+ * of {@link #getTokenDisplayName} for the corresponding token type.
+ *
+ * @see #getTokenDisplayName
+ * @return The display names of all tokens defined in the grammar.
+ */
+ public String[] getTokenDisplayNames() {
+ int numTokens = getMaxTokenType();
+ String[] tokenNames = new String[numTokens+1];
+ for (int i = 0; i < tokenNames.length; i++) {
+ tokenNames[i] = getTokenDisplayName(i);
+ }
+
+ return tokenNames;
+ }
+
+ /**
+ * Gets the literal names assigned to tokens in the grammar.
+ */
+
+ public String[] getTokenLiteralNames() {
+ int numTokens = getMaxTokenType();
+ String[] literalNames = new String[numTokens+1];
+ for (int i = 0; i < Math.min(literalNames.length, typeToStringLiteralList.size()); i++) {
+ literalNames[i] = typeToStringLiteralList.get(i);
+ }
+
+ for (Map.Entry<String, Integer> entry : stringLiteralToTypeMap.entrySet()) {
+ if (entry.getValue() >= 0 && entry.getValue() < literalNames.length && literalNames[entry.getValue()] == null) {
+ literalNames[entry.getValue()] = entry.getKey();
+ }
+ }
+
+ return literalNames;
+ }
+
+ /**
+ * Gets the symbolic names assigned to tokens in the grammar.
+ */
+
+ public String[] getTokenSymbolicNames() {
+ int numTokens = getMaxTokenType();
+ String[] symbolicNames = new String[numTokens+1];
+ for (int i = 0; i < Math.min(symbolicNames.length, typeToTokenList.size()); i++) {
+ if (typeToTokenList.get(i) == null || typeToTokenList.get(i).startsWith(AUTO_GENERATED_TOKEN_NAME_PREFIX)) {
+ continue;
+ }
+
+ symbolicNames[i] = typeToTokenList.get(i);
+ }
+
+ return symbolicNames;
+ }
+
+ /**
+ * Gets a {@link Vocabulary} instance describing the vocabulary used by the
+ * grammar.
+ */
+
+ public Vocabulary getVocabulary() {
+ return new VocabularyImpl(getTokenLiteralNames(), getTokenSymbolicNames());
+ }
+
+ /** Given an arbitrarily complex SemanticContext, walk the "tree" and get display string.
+ * Pull predicates from grammar text.
+ */
+ public String getSemanticContextDisplayString(SemanticContext semctx) {
+ if ( semctx instanceof SemanticContext.Predicate ) {
+ return getPredicateDisplayString((SemanticContext.Predicate)semctx);
+ }
+ if ( semctx instanceof SemanticContext.AND ) {
+ SemanticContext.AND and = (SemanticContext.AND)semctx;
+ return joinPredicateOperands(and, " and ");
+ }
+ if ( semctx instanceof SemanticContext.OR ) {
+ SemanticContext.OR or = (SemanticContext.OR)semctx;
+ return joinPredicateOperands(or, " or ");
+ }
+ return semctx.toString();
+ }
+
+ public String joinPredicateOperands(SemanticContext.Operator op, String separator) {
+ StringBuilder buf = new StringBuilder();
+ for (SemanticContext operand : op.getOperands()) {
+ if (buf.length() > 0) {
+ buf.append(separator);
+ }
+
+ buf.append(getSemanticContextDisplayString(operand));
+ }
+
+ return buf.toString();
+ }
+
+ public LinkedHashMap<Integer, PredAST> getIndexToPredicateMap() {
+ LinkedHashMap<Integer, PredAST> indexToPredMap = new LinkedHashMap<Integer, PredAST>();
+ for (Rule r : rules.values()) {
+ for (ActionAST a : r.actions) {
+ if (a instanceof PredAST) {
+ PredAST p = (PredAST) a;
+ indexToPredMap.put(sempreds.get(p), p);
+ }
+ }
+ }
+ return indexToPredMap;
+ }
+
+ public String getPredicateDisplayString(SemanticContext.Predicate pred) {
+ if ( indexToPredMap==null ) {
+ indexToPredMap = getIndexToPredicateMap();
+ }
+ ActionAST actionAST = indexToPredMap.get(pred.predIndex);
+ return actionAST.getText();
+ }
+
+ /** What is the max char value possible for this grammar's target? Use
+ * unicode max if no target defined.
+ */
+ public int getMaxCharValue() {
+ return org.antlr.v4.runtime.Lexer.MAX_CHAR_VALUE;
+// if ( generator!=null ) {
+// return generator.target.getMaxCharValue(generator);
+// }
+// else {
+// return Label.MAX_CHAR_VALUE;
+// }
+ }
+
+ /** Return a set of all possible token or char types for this grammar */
+ public IntSet getTokenTypes() {
+ if ( isLexer() ) {
+ return getAllCharValues();
+ }
+ return IntervalSet.of(Token.MIN_USER_TOKEN_TYPE, getMaxTokenType());
+ }
+
+ /** Return min to max char as defined by the target.
+ * If no target, use max unicode char value.
+ */
+ public IntSet getAllCharValues() {
+ return IntervalSet.of(Lexer.MIN_CHAR_VALUE, getMaxCharValue());
+ }
+
+ /** How many token types have been allocated so far? */
+ public int getMaxTokenType() {
+ return typeToTokenList.size() - 1; // don't count 0 (invalid)
+ }
+
+ /** Return a new unique integer in the token type space */
+ public int getNewTokenType() {
+ maxTokenType++;
+ return maxTokenType;
+ }
+
+ /** Return a new unique integer in the channel value space. */
+ public int getNewChannelNumber() {
+ maxChannelType++;
+ return maxChannelType;
+ }
+
+ public void importTokensFromTokensFile() {
+ String vocab = getOptionString("tokenVocab");
+ if ( vocab!=null ) {
+ TokenVocabParser vparser = new TokenVocabParser(this);
+ Map<String,Integer> tokens = vparser.load();
+ tool.log("grammar", "tokens=" + tokens);
+ for (String t : tokens.keySet()) {
+ if ( t.charAt(0)=='\'' ) defineStringLiteral(t, tokens.get(t));
+ else defineTokenName(t, tokens.get(t));
+ }
+ }
+ }
+
+ public void importVocab(Grammar importG) {
+ for (String tokenName: importG.tokenNameToTypeMap.keySet()) {
+ defineTokenName(tokenName, importG.tokenNameToTypeMap.get(tokenName));
+ }
+ for (String tokenName: importG.stringLiteralToTypeMap.keySet()) {
+ defineStringLiteral(tokenName, importG.stringLiteralToTypeMap.get(tokenName));
+ }
+ for (Map.Entry<String, Integer> channel : importG.channelNameToValueMap.entrySet()) {
+ defineChannelName(channel.getKey(), channel.getValue());
+ }
+// this.tokenNameToTypeMap.putAll( importG.tokenNameToTypeMap );
+// this.stringLiteralToTypeMap.putAll( importG.stringLiteralToTypeMap );
+ int max = Math.max(this.typeToTokenList.size(), importG.typeToTokenList.size());
+ Utils.setSize(typeToTokenList, max);
+ for (int ttype=0; ttype<importG.typeToTokenList.size(); ttype++) {
+ maxTokenType = Math.max(maxTokenType, ttype);
+ this.typeToTokenList.set(ttype, importG.typeToTokenList.get(ttype));
+ }
+
+ max = Math.max(this.channelValueToNameList.size(), importG.channelValueToNameList.size());
+ Utils.setSize(channelValueToNameList, max);
+ for (int channelValue = 0; channelValue < importG.channelValueToNameList.size(); channelValue++) {
+ maxChannelType = Math.max(maxChannelType, channelValue);
+ this.channelValueToNameList.set(channelValue, importG.channelValueToNameList.get(channelValue));
+ }
+ }
+
+ public int defineTokenName(String name) {
+ Integer prev = tokenNameToTypeMap.get(name);
+ if ( prev==null ) return defineTokenName(name, getNewTokenType());
+ return prev;
+ }
+
+ public int defineTokenName(String name, int ttype) {
+ Integer prev = tokenNameToTypeMap.get(name);
+ if ( prev!=null ) return prev;
+ tokenNameToTypeMap.put(name, ttype);
+ setTokenForType(ttype, name);
+ maxTokenType = Math.max(maxTokenType, ttype);
+ return ttype;
+ }
+
+ public int defineStringLiteral(String lit) {
+ if ( stringLiteralToTypeMap.containsKey(lit) ) {
+ return stringLiteralToTypeMap.get(lit);
+ }
+ return defineStringLiteral(lit, getNewTokenType());
+
+ }
+
+ public int defineStringLiteral(String lit, int ttype) {
+ if ( !stringLiteralToTypeMap.containsKey(lit) ) {
+ stringLiteralToTypeMap.put(lit, ttype);
+ // track in reverse index too
+ if ( ttype>=typeToStringLiteralList.size() ) {
+ Utils.setSize(typeToStringLiteralList, ttype+1);
+ }
+ typeToStringLiteralList.set(ttype, lit);
+
+ setTokenForType(ttype, lit);
+ return ttype;
+ }
+ return Token.INVALID_TYPE;
+ }
+
+ public int defineTokenAlias(String name, String lit) {
+ int ttype = defineTokenName(name);
+ stringLiteralToTypeMap.put(lit, ttype);
+ setTokenForType(ttype, name);
+ return ttype;
+ }
+
+ public void setTokenForType(int ttype, String text) {
+ if (ttype == Token.EOF) {
+ // ignore EOF, it will be reported as an error separately
+ return;
+ }
+
+ if ( ttype>=typeToTokenList.size() ) {
+ Utils.setSize(typeToTokenList, ttype+1);
+ }
+ String prevToken = typeToTokenList.get(ttype);
+ if ( prevToken==null || prevToken.charAt(0)=='\'' ) {
+ // only record if nothing there before or if thing before was a literal
+ typeToTokenList.set(ttype, text);
+ }
+ }
+
+ /**
+ * Define a token channel with a specified name.
+ *
+ * <p>
+ * If a channel with the specified name already exists, the previously
+ * assigned channel value is returned.</p>
+ *
+ * @param name The channel name.
+ * @return The constant channel value assigned to the channel.
+ */
+ public int defineChannelName(String name) {
+ Integer prev = channelNameToValueMap.get(name);
+ if (prev == null) {
+ return defineChannelName(name, getNewChannelNumber());
+ }
+
+ return prev;
+ }
+
+ /**
+ * Define a token channel with a specified name.
+ *
+ * <p>
+ * If a channel with the specified name already exists, the previously
+ * assigned channel value is not altered.</p>
+ *
+ * @param name The channel name.
+ * @return The constant channel value assigned to the channel.
+ */
+ public int defineChannelName(String name, int value) {
+ Integer prev = channelNameToValueMap.get(name);
+ if (prev != null) {
+ return prev;
+ }
+
+ channelNameToValueMap.put(name, value);
+ setChannelNameForValue(value, name);
+ maxChannelType = Math.max(maxChannelType, value);
+ return value;
+ }
+
+ /**
+ * Sets the channel name associated with a particular channel value.
+ *
+ * <p>
+ * If a name has already been assigned to the channel with constant value
+ * {@code channelValue}, this method does nothing.</p>
+ *
+ * @param channelValue The constant value for the channel.
+ * @param name The channel name.
+ */
+ public void setChannelNameForValue(int channelValue, String name) {
+ if (channelValue >= channelValueToNameList.size()) {
+ Utils.setSize(channelValueToNameList, channelValue + 1);
+ }
+
+ String prevChannel = channelValueToNameList.get(channelValue);
+ if (prevChannel == null) {
+ channelValueToNameList.set(channelValue, name);
+ }
+ }
+
+ // no isolated attr at grammar action level
+ @Override
+ public Attribute resolveToAttribute(String x, ActionAST node) {
+ return null;
+ }
+
+ // no $x.y makes sense here
+ @Override
+ public Attribute resolveToAttribute(String x, String y, ActionAST node) {
+ return null;
+ }
+
+ @Override
+ public boolean resolvesToLabel(String x, ActionAST node) { return false; }
+
+ @Override
+ public boolean resolvesToListLabel(String x, ActionAST node) { return false; }
+
+ @Override
+ public boolean resolvesToToken(String x, ActionAST node) { return false; }
+
+ @Override
+ public boolean resolvesToAttributeDict(String x, ActionAST node) {
+ return false;
+ }
+
+ /** Given a grammar type, what should be the default action scope?
+ * If I say @members in a COMBINED grammar, for example, the
+ * default scope should be "parser".
+ */
+ public String getDefaultActionScope() {
+ switch ( getType() ) {
+ case ANTLRParser.LEXER :
+ return "lexer";
+ case ANTLRParser.PARSER :
+ case ANTLRParser.COMBINED :
+ return "parser";
+ }
+ return null;
+ }
+
+ public int getType() {
+ if ( ast!=null ) return ast.grammarType;
+ return 0;
+ }
+
+ public org.antlr.runtime.TokenStream getTokenStream() {
+ if ( ast!=null ) return ast.tokenStream;
+ return null;
+ }
+
+ public boolean isLexer() { return getType()==ANTLRParser.LEXER; }
+ public boolean isParser() { return getType()==ANTLRParser.PARSER; }
+ public boolean isCombined() { return getType()==ANTLRParser.COMBINED; }
+
+ /** Is id a valid token name? Does id start with an uppercase letter? */
+ public static boolean isTokenName(String id) {
+ return Character.isUpperCase(id.charAt(0));
+ }
+
+ public String getTypeString() {
+ if ( ast==null ) return null;
+ return ANTLRParser.tokenNames[getType()].toLowerCase();
+ }
+
+ public static String getGrammarTypeToFileNameSuffix(int type) {
+ switch ( type ) {
+ case ANTLRParser.LEXER : return "Lexer";
+ case ANTLRParser.PARSER : return "Parser";
+ // if combined grammar, gen Parser and Lexer will be done later
+ // TODO: we are separate now right?
+ case ANTLRParser.COMBINED : return "Parser";
+ default :
+ return "<invalid>";
+ }
+ }
+
+ public String getOptionString(String key) { return ast.getOptionString(key); }
+
+ /** Given ^(TOKEN_REF ^(OPTIONS ^(ELEMENT_OPTIONS (= assoc right))))
+ * set option assoc=right in TOKEN_REF.
+ */
+ public static void setNodeOptions(GrammarAST node, GrammarAST options) {
+ if ( options==null ) return;
+ GrammarASTWithOptions t = (GrammarASTWithOptions)node;
+ if ( t.getChildCount()==0 || options.getChildCount()==0 ) return;
+ for (Object o : options.getChildren()) {
+ GrammarAST c = (GrammarAST)o;
+ if ( c.getType()==ANTLRParser.ASSIGN ) {
+ t.setOption(c.getChild(0).getText(), (GrammarAST)c.getChild(1));
+ }
+ else {
+ t.setOption(c.getText(), null); // no arg such as ID<VarNodeType>
+ }
+ }
+ }
+
+ /** Return list of (TOKEN_NAME node, 'literal' node) pairs */
+ public static List<Pair<GrammarAST,GrammarAST>> getStringLiteralAliasesFromLexerRules(GrammarRootAST ast) {
+ String[] patterns = {
+ "(RULE %name:TOKEN_REF (BLOCK (ALT %lit:STRING_LITERAL)))",
+ "(RULE %name:TOKEN_REF (BLOCK (ALT %lit:STRING_LITERAL ACTION)))",
+ "(RULE %name:TOKEN_REF (BLOCK (ALT %lit:STRING_LITERAL SEMPRED)))",
+ "(RULE %name:TOKEN_REF (BLOCK (LEXER_ALT_ACTION (ALT %lit:STRING_LITERAL) .)))",
+ "(RULE %name:TOKEN_REF (BLOCK (LEXER_ALT_ACTION (ALT %lit:STRING_LITERAL) . .)))",
+ "(RULE %name:TOKEN_REF (BLOCK (LEXER_ALT_ACTION (ALT %lit:STRING_LITERAL) (LEXER_ACTION_CALL . .))))",
+ "(RULE %name:TOKEN_REF (BLOCK (LEXER_ALT_ACTION (ALT %lit:STRING_LITERAL) . (LEXER_ACTION_CALL . .))))",
+ "(RULE %name:TOKEN_REF (BLOCK (LEXER_ALT_ACTION (ALT %lit:STRING_LITERAL) (LEXER_ACTION_CALL . .) .)))",
+ // TODO: allow doc comment in there
+ };
+ GrammarASTAdaptor adaptor = new GrammarASTAdaptor(ast.token.getInputStream());
+ org.antlr.runtime.tree.TreeWizard wiz = new org.antlr.runtime.tree.TreeWizard(adaptor,ANTLRParser.tokenNames);
+ List<Pair<GrammarAST,GrammarAST>> lexerRuleToStringLiteral =
+ new ArrayList<Pair<GrammarAST,GrammarAST>>();
+
+ List<GrammarAST> ruleNodes = ast.getNodesWithType(ANTLRParser.RULE);
+ if ( ruleNodes==null || ruleNodes.isEmpty() ) return null;
+
+ for (GrammarAST r : ruleNodes) {
+ //tool.log("grammar", r.toStringTree());
+// System.out.println("chk: "+r.toStringTree());
+ org.antlr.runtime.tree.Tree name = r.getChild(0);
+ if ( name.getType()==ANTLRParser.TOKEN_REF ) {
+ // check rule against patterns
+ boolean isLitRule;
+ for (String pattern : patterns) {
+ isLitRule =
+ defAlias(r, pattern, wiz, lexerRuleToStringLiteral);
+ if ( isLitRule ) break;
+ }
+// if ( !isLitRule ) System.out.println("no pattern matched");
+ }
+ }
+ return lexerRuleToStringLiteral;
+ }
+
+ protected static boolean defAlias(GrammarAST r, String pattern,
+ org.antlr.runtime.tree.TreeWizard wiz,
+ List<Pair<GrammarAST,GrammarAST>> lexerRuleToStringLiteral)
+ {
+ HashMap<String, Object> nodes = new HashMap<String, Object>();
+ if ( wiz.parse(r, pattern, nodes) ) {
+ GrammarAST litNode = (GrammarAST)nodes.get("lit");
+ GrammarAST nameNode = (GrammarAST)nodes.get("name");
+ Pair<GrammarAST, GrammarAST> pair =
+ new Pair<GrammarAST, GrammarAST>(nameNode, litNode);
+ lexerRuleToStringLiteral.add(pair);
+ return true;
+ }
+ return false;
+ }
+
+ public Set<String> getStringLiterals() {
+ final Set<String> strings = new LinkedHashSet<String>();
+ GrammarTreeVisitor collector = new GrammarTreeVisitor() {
+ @Override
+ public void stringRef(TerminalAST ref) {
+ strings.add(ref.getText());
+ }
+ @Override
+ public ErrorManager getErrorManager() { return tool.errMgr; }
+ };
+ collector.visitGrammar(ast);
+ return strings;
+ }
+
+ public void setLookaheadDFA(int decision, DFA lookaheadDFA) {
+ decisionDFAs.put(decision, lookaheadDFA);
+ }
+
+ public static Map<Integer, Interval> getStateToGrammarRegionMap(GrammarRootAST ast, IntervalSet grammarTokenTypes) {
+ Map<Integer, Interval> stateToGrammarRegionMap = new HashMap<Integer, Interval>();
+ if ( ast==null ) return stateToGrammarRegionMap;
+
+ List<GrammarAST> nodes = ast.getNodesWithType(grammarTokenTypes);
+ for (GrammarAST n : nodes) {
+ if (n.atnState != null) {
+ Interval tokenRegion = Interval.of(n.getTokenStartIndex(), n.getTokenStopIndex());
+ org.antlr.runtime.tree.Tree ruleNode = null;
+ // RULEs, BLOCKs of transformed recursive rules point to original token interval
+ switch ( n.getType() ) {
+ case ANTLRParser.RULE :
+ ruleNode = n;
+ break;
+ case ANTLRParser.BLOCK :
+ case ANTLRParser.CLOSURE :
+ ruleNode = n.getAncestor(ANTLRParser.RULE);
+ break;
+ }
+ if ( ruleNode instanceof RuleAST ) {
+ String ruleName = ((RuleAST) ruleNode).getRuleName();
+ Rule r = ast.g.getRule(ruleName);
+ if ( r instanceof LeftRecursiveRule ) {
+ RuleAST originalAST = ((LeftRecursiveRule) r).getOriginalAST();
+ tokenRegion = Interval.of(originalAST.getTokenStartIndex(), originalAST.getTokenStopIndex());
+ }
+ }
+ stateToGrammarRegionMap.put(n.atnState.stateNumber, tokenRegion);
+ }
+ }
+ return stateToGrammarRegionMap;
+ }
+
+ /** Given an ATN state number, return the token index range within the grammar from which that ATN state was derived. */
+ public Interval getStateToGrammarRegion(int atnStateNumber) {
+ if ( stateToGrammarRegionMap==null ) {
+ stateToGrammarRegionMap = getStateToGrammarRegionMap(ast, null); // map all nodes with non-null atn state ptr
+ }
+ if ( stateToGrammarRegionMap==null ) return Interval.INVALID;
+
+ return stateToGrammarRegionMap.get(atnStateNumber);
+ }
+
+ public LexerInterpreter createLexerInterpreter(CharStream input) {
+ if (this.isParser()) {
+ throw new IllegalStateException("A lexer interpreter can only be created for a lexer or combined grammar.");
+ }
+
+ if (this.isCombined()) {
+ return implicitLexer.createLexerInterpreter(input);
+ }
+
+ char[] serializedAtn = ATNSerializer.getSerializedAsChars(atn);
+ ATN deserialized = new ATNDeserializer().deserialize(serializedAtn);
+ return new LexerInterpreter(fileName, getVocabulary(), Arrays.asList(getRuleNames()), ((LexerGrammar)this).modes.keySet(), deserialized, input);
+ }
+
+ /** @since 4.5.1 */
+ public GrammarParserInterpreter createGrammarParserInterpreter(TokenStream tokenStream) {
+ if (this.isLexer()) {
+ throw new IllegalStateException("A parser interpreter can only be created for a parser or combined grammar.");
+ }
+ char[] serializedAtn = ATNSerializer.getSerializedAsChars(atn);
+ ATN deserialized = new ATNDeserializer().deserialize(serializedAtn);
+ return new GrammarParserInterpreter(this, deserialized, tokenStream);
+ }
+
+ public ParserInterpreter createParserInterpreter(TokenStream tokenStream) {
+ if (this.isLexer()) {
+ throw new IllegalStateException("A parser interpreter can only be created for a parser or combined grammar.");
+ }
+
+ char[] serializedAtn = ATNSerializer.getSerializedAsChars(atn);
+ ATN deserialized = new ATNDeserializer().deserialize(serializedAtn);
+ return new ParserInterpreter(fileName, getVocabulary(), Arrays.asList(getRuleNames()), deserialized, tokenStream);
+ }
+}
diff --git a/tool/src/org/antlr/v4/tool/GrammarInterpreterRuleContext.java b/tool/src/org/antlr/v4/tool/GrammarInterpreterRuleContext.java
new file mode 100644
index 0000000..8457a6a
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/GrammarInterpreterRuleContext.java
@@ -0,0 +1,57 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.v4.tool;
+
+import org.antlr.v4.runtime.InterpreterRuleContext;
+import org.antlr.v4.runtime.ParserRuleContext;
+
+/** An {@link InterpreterRuleContext} that knows which alternative
+ * for a rule was matched.
+ *
+ * @see GrammarParserInterpreter
+ * @since 4.5.1
+ */
+public class GrammarInterpreterRuleContext extends InterpreterRuleContext {
+ protected int outerAltNum = 1;
+
+ public GrammarInterpreterRuleContext(ParserRuleContext parent, int invokingStateNumber, int ruleIndex) {
+ super(parent, invokingStateNumber, ruleIndex);
+ }
+
+ /** The predicted outermost alternative for the rule associated
+ * with this context object. If this node left recursive, the true original
+ * outermost alternative is returned.
+ */
+ public int getOuterAltNum() { return outerAltNum; }
+
+ public void setOuterAltNum(int outerAltNum) {
+ this.outerAltNum = outerAltNum;
+ }
+}
diff --git a/tool/src/org/antlr/v4/tool/GrammarParserInterpreter.java b/tool/src/org/antlr/v4/tool/GrammarParserInterpreter.java
new file mode 100644
index 0000000..9361b40
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/GrammarParserInterpreter.java
@@ -0,0 +1,474 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.antlr.v4.tool;
+
+import org.antlr.v4.runtime.BailErrorStrategy;
+import org.antlr.v4.runtime.DefaultErrorStrategy;
+import org.antlr.v4.runtime.InputMismatchException;
+import org.antlr.v4.runtime.InterpreterRuleContext;
+import org.antlr.v4.runtime.Parser;
+import org.antlr.v4.runtime.ParserInterpreter;
+import org.antlr.v4.runtime.ParserRuleContext;
+import org.antlr.v4.runtime.RecognitionException;
+import org.antlr.v4.runtime.Token;
+import org.antlr.v4.runtime.TokenStream;
+import org.antlr.v4.runtime.Vocabulary;
+import org.antlr.v4.runtime.atn.ATN;
+import org.antlr.v4.runtime.atn.ATNDeserializer;
+import org.antlr.v4.runtime.atn.ATNSerializer;
+import org.antlr.v4.runtime.atn.ATNState;
+import org.antlr.v4.runtime.atn.DecisionState;
+import org.antlr.v4.runtime.atn.PredictionMode;
+import org.antlr.v4.runtime.atn.RuleStartState;
+import org.antlr.v4.runtime.atn.StarLoopEntryState;
+import org.antlr.v4.runtime.tree.Trees;
+
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.Collection;
+import java.util.List;
+
+/** A heavier weight {@link ParserInterpreter} that creates parse trees
+ * that track alternative numbers for subtree roots.
+ *
+ * @since 4.5.1
+ *
+ */
+public class GrammarParserInterpreter extends ParserInterpreter {
+ /** The grammar associated with this interpreter. Unlike the
+ * {@link ParserInterpreter} from the standard distribution,
+ * this can reference Grammar, which is in the tools area not
+ * purely runtime.
+ */
+ protected final Grammar g;
+
+ protected BitSet decisionStatesThatSetOuterAltNumInContext;
+
+ /** Cache {@link LeftRecursiveRule#getPrimaryAlts()} and
+ * {@link LeftRecursiveRule#getRecursiveOpAlts()} for states in
+ * {@link #decisionStatesThatSetOuterAltNumInContext}. It only
+ * caches decisions in left-recursive rules.
+ */
+ protected int[][] stateToAltsMap;
+
+ public GrammarParserInterpreter(Grammar g,
+ String grammarFileName,
+ Vocabulary vocabulary,
+ Collection<String> ruleNames,
+ ATN atn,
+ TokenStream input) {
+ super(grammarFileName, vocabulary, ruleNames, atn, input);
+ this.g = g;
+ }
+
+ public GrammarParserInterpreter(Grammar g, ATN atn, TokenStream input) {
+ super(g.fileName, g.getVocabulary(),
+ Arrays.asList(g.getRuleNames()),
+ atn, // must run ATN through serializer to set some state flags
+ input);
+ this.g = g;
+ decisionStatesThatSetOuterAltNumInContext = findOuterMostDecisionStates();
+ stateToAltsMap = new int[g.atn.states.size()][];
+ }
+
+ @Override
+ protected InterpreterRuleContext createInterpreterRuleContext(ParserRuleContext parent,
+ int invokingStateNumber,
+ int ruleIndex)
+ {
+ return new GrammarInterpreterRuleContext(parent, invokingStateNumber, ruleIndex);
+ }
+
+ @Override
+ public void reset() {
+ super.reset();
+ overrideDecisionRoot = null;
+ }
+
+ /** identify the ATN states where we need to set the outer alt number.
+ * For regular rules, that's the block at the target to rule start state.
+ * For left-recursive rules, we track the primary block, which looks just
+ * like a regular rule's outer block, and the star loop block (always
+ * there even if 1 alt).
+ */
+ public BitSet findOuterMostDecisionStates() {
+ BitSet track = new BitSet(atn.states.size());
+ int numberOfDecisions = atn.getNumberOfDecisions();
+ for (int i = 0; i < numberOfDecisions; i++) {
+ DecisionState decisionState = atn.getDecisionState(i);
+ RuleStartState startState = atn.ruleToStartState[decisionState.ruleIndex];
+ // Look for StarLoopEntryState that is in any left recursive rule
+ if ( decisionState instanceof StarLoopEntryState) {
+ StarLoopEntryState loopEntry = (StarLoopEntryState)decisionState;
+ if ( loopEntry.isPrecedenceDecision ) {
+ // Recursive alts always result in a (...)* in the transformed
+ // left recursive rule and that always has a BasicBlockStartState
+ // even if just 1 recursive alt exists.
+ ATNState blockStart = loopEntry.transition(0).target;
+ // track the StarBlockStartState associated with the recursive alternatives
+ track.set(blockStart.stateNumber);
+ }
+ }
+ else if ( startState.transition(0).target == decisionState ) {
+ // always track outermost block for any rule if it exists
+ track.set(decisionState.stateNumber);
+ }
+ }
+ return track;
+ }
+
+ /** Override this method so that we can record which alternative
+ * was taken at each decision point. For non-left recursive rules,
+ * it's simple. Set decisionStatesThatSetOuterAltNumInContext
+ * indicates which decision states should set the outer alternative number.
+ *
+ * Left recursive rules are much more complicated to deal with:
+ * there is typically a decision for the primary alternatives and a
+ * decision to choose between the recursive operator alternatives.
+ * For example, the following left recursive rule has two primary and 2
+ * recursive alternatives.</p>
+ *
+ e : e '*' e
+ | '-' INT
+ | e '+' e
+ | ID
+ ;
+
+ * <p>ANTLR rewrites that rule to be</p>
+
+ e[int precedence]
+ : ('-' INT | ID)
+ ( {...}? '*' e[5]
+ | {...}? '+' e[3]
+ )*
+ ;
+
+ *
+ * <p>So, there are two decisions associated with picking the outermost alt.
+ * This complicates our tracking significantly. The outermost alternative number
+ * is a function of the decision (ATN state) within a left recursive rule and the
+ * predicted alternative coming back from adaptivePredict().
+ *
+ * We use stateToAltsMap as a cache to avoid expensive calls to
+ * getRecursiveOpAlts().
+ */
+ @Override
+ protected int visitDecisionState(DecisionState p) {
+ int predictedAlt = super.visitDecisionState(p);
+ if( p.getNumberOfTransitions() > 1) {
+// System.out.println("decision "+p.decision+": "+predictedAlt);
+ if( p.decision == this.overrideDecision &&
+ this._input.index() == this.overrideDecisionInputIndex )
+ {
+ overrideDecisionRoot = (GrammarInterpreterRuleContext)getContext();
+ }
+ }
+
+ GrammarInterpreterRuleContext ctx = (GrammarInterpreterRuleContext)_ctx;
+ if ( decisionStatesThatSetOuterAltNumInContext.get(p.stateNumber) ) {
+ ctx.outerAltNum = predictedAlt;
+ Rule r = g.getRule(p.ruleIndex);
+ if ( atn.ruleToStartState[r.index].isLeftRecursiveRule ) {
+ int[] alts = stateToAltsMap[p.stateNumber];
+ LeftRecursiveRule lr = (LeftRecursiveRule) g.getRule(p.ruleIndex);
+ if (p.getStateType() == ATNState.BLOCK_START) {
+ if ( alts==null ) {
+ alts = lr.getPrimaryAlts();
+ stateToAltsMap[p.stateNumber] = alts; // cache it
+ }
+ }
+ else if ( p.getStateType() == ATNState.STAR_BLOCK_START ) {
+ if ( alts==null ) {
+ alts = lr.getRecursiveOpAlts();
+ stateToAltsMap[p.stateNumber] = alts; // cache it
+ }
+ }
+ ctx.outerAltNum = alts[predictedAlt];
+ }
+ }
+
+ return predictedAlt;
+ }
+
+ /** Given an ambiguous parse information, return the list of ambiguous parse trees.
+ * An ambiguity occurs when a specific token sequence can be recognized
+ * in more than one way by the grammar. These ambiguities are detected only
+ * at decision points.
+ *
+ * The list of trees includes the actual interpretation (that for
+ * the minimum alternative number) and all ambiguous alternatives.
+ * The actual interpretation is always first.
+ *
+ * This method reuses the same physical input token stream used to
+ * detect the ambiguity by the original parser in the first place.
+ * This method resets/seeks within but does not alter originalParser.
+ *
+ * The trees are rooted at the node whose start..stop token indices
+ * include the start and stop indices of this ambiguity event. That is,
+ * the trees returned will always include the complete ambiguous subphrase
+ * identified by the ambiguity event. The subtrees returned will
+ * also always contain the node associated with the overridden decision.
+ *
+ * Be aware that this method does NOT notify error or parse listeners as
+ * it would trigger duplicate or otherwise unwanted events.
+ *
+ * This uses a temporary ParserATNSimulator and a ParserInterpreter
+ * so we don't mess up any statistics, event lists, etc...
+ * The parse tree constructed while identifying/making ambiguityInfo is
+ * not affected by this method as it creates a new parser interp to
+ * get the ambiguous interpretations.
+ *
+ * Nodes in the returned ambig trees are independent of the original parse
+ * tree (constructed while identifying/creating ambiguityInfo).
+ *
+ * @since 4.5.1
+ *
+ * @param g From which grammar should we drive alternative
+ * numbers and alternative labels.
+ *
+ * @param originalParser The parser used to create ambiguityInfo; it
+ * is not modified by this routine and can be either
+ * a generated or interpreted parser. It's token
+ * stream *is* reset/seek()'d.
+ * @param tokens A stream of tokens to use with the temporary parser.
+ * This will often be just the token stream within the
+ * original parser but here it is for flexibility.
+ *
+ * @param decision Which decision to try different alternatives for.
+ *
+ * @param alts The set of alternatives to try while re-parsing.
+ *
+ * @param startIndex The index of the first token of the ambiguous
+ * input or other input of interest.
+ *
+ * @param stopIndex The index of the last token of the ambiguous input.
+ * The start and stop indexes are used primarily to
+ * identify how much of the resulting parse tree
+ * to return.
+ *
+ * @param startRuleIndex The start rule for the entire grammar, not
+ * the ambiguous decision. We re-parse the entire input
+ * and so we need the original start rule.
+ *
+ * @return The list of all possible interpretations of
+ * the input for the decision in ambiguityInfo.
+ * The actual interpretation chosen by the parser
+ * is always given first because this method
+ * retests the input in alternative order and
+ * ANTLR always resolves ambiguities by choosing
+ * the first alternative that matches the input.
+ * The subtree returned
+ *
+ * @throws RecognitionException Throws upon syntax error while matching
+ * ambig input.
+ */
+ public static List<ParserRuleContext> getAllPossibleParseTrees(Grammar g,
+ Parser originalParser,
+ TokenStream tokens,
+ int decision,
+ BitSet alts,
+ int startIndex,
+ int stopIndex,
+ int startRuleIndex)
+ throws RecognitionException
+ {
+ List<ParserRuleContext> trees = new ArrayList<ParserRuleContext>();
+ // Create a new parser interpreter to parse the ambiguous subphrase
+ ParserInterpreter parser = deriveTempParserInterpreter(g, originalParser, tokens);
+
+ // get ambig trees
+ int alt = alts.nextSetBit(0);
+ while (alt >= 0) {
+ // re-parse entire input for all ambiguous alternatives
+ // (don't have to do first as it's been parsed, but do again for simplicity
+ // using this temp parser.)
+ parser.reset();
+ parser.addDecisionOverride(decision, startIndex, alt);
+ ParserRuleContext t = parser.parse(startRuleIndex);
+ GrammarInterpreterRuleContext ambigSubTree =
+ (GrammarInterpreterRuleContext) Trees.getRootOfSubtreeEnclosingRegion(t, startIndex, stopIndex);
+ // Use higher of overridden decision tree or tree enclosing all tokens
+ if ( Trees.isAncestorOf(parser.getOverrideDecisionRoot(), ambigSubTree) ) {
+ ambigSubTree = (GrammarInterpreterRuleContext)parser.getOverrideDecisionRoot();
+ }
+ trees.add(ambigSubTree);
+ alt = alts.nextSetBit(alt + 1);
+ }
+
+ return trees;
+ }
+
+
+ /** Return a list of parse trees, one for each alternative in a decision
+ * given the same input.
+ *
+ * Very similar to {@link #getAllPossibleParseTrees} except
+ * that it re-parses the input for every alternative in a decision,
+ * not just the ambiguous ones (there is no alts parameter here).
+ * This method also tries to reduce the size of the parse trees
+ * by stripping away children of the tree that are completely out of range
+ * of startIndex..stopIndex. Also, because errors are expected, we
+ * use a specialized error handler that more or less bails out
+ * but that also consumes the first erroneous token at least. This
+ * ensures that an error node will be in the parse tree for display.
+ *
+ * NOTES:
+ // we must parse the entire input now with decision overrides
+ // we cannot parse a subset because it could be that a decision
+ // above our decision of interest needs to read way past
+ // lookaheadInfo.stopIndex. It seems like there is no escaping
+ // the use of a full and complete token stream if we are
+ // resetting to token index 0 and re-parsing from the start symbol.
+ // It's not easy to restart parsing somewhere in the middle like a
+ // continuation because our call stack does not match the
+ // tree stack because of left recursive rule rewriting. grrrr!
+ *
+ * @since 4.5.1
+ */
+ public static List<ParserRuleContext> getLookaheadParseTrees(Grammar g,
+ ParserInterpreter originalParser,
+ TokenStream tokens,
+ int startRuleIndex,
+ int decision,
+ int startIndex,
+ int stopIndex)
+ {
+ List<ParserRuleContext> trees = new ArrayList<ParserRuleContext>();
+ // Create a new parser interpreter to parse the ambiguous subphrase
+ ParserInterpreter parser = deriveTempParserInterpreter(g, originalParser, tokens);
+ BailButConsumeErrorStrategy errorHandler = new BailButConsumeErrorStrategy();
+ parser.setErrorHandler(errorHandler);
+
+ DecisionState decisionState = originalParser.getATN().decisionToState.get(decision);
+
+ for (int alt=1; alt<=decisionState.getTransitions().length; alt++) {
+ // re-parse entire input for all ambiguous alternatives
+ // (don't have to do first as it's been parsed, but do again for simplicity
+ // using this temp parser.)
+ parser.reset();
+ parser.addDecisionOverride(decision, startIndex, alt);
+ ParserRuleContext tt = parser.parse(startRuleIndex);
+ int stopTreeAt = stopIndex;
+ if ( errorHandler.firstErrorTokenIndex>=0 ) {
+ stopTreeAt = errorHandler.firstErrorTokenIndex; // cut off rest at first error
+ }
+ ParserRuleContext subtree =
+ Trees.getRootOfSubtreeEnclosingRegion(tt,
+ startIndex,
+ stopTreeAt);
+ // Use higher of overridden decision tree or tree enclosing all tokens
+ if ( Trees.isAncestorOf(parser.getOverrideDecisionRoot(), subtree) ) {
+ subtree = parser.getOverrideDecisionRoot();
+ }
+ Trees.stripChildrenOutOfRange(subtree, parser.getOverrideDecisionRoot(), startIndex, stopTreeAt);
+ trees.add(subtree);
+ }
+
+ return trees;
+ }
+
+ /** Derive a new parser from an old one that has knowledge of the grammar.
+ * The Grammar object is used to correctly compute outer alternative
+ * numbers for parse tree nodes. A parser of the same type is created
+ * for subclasses of {@link ParserInterpreter}.
+ */
+ public static ParserInterpreter deriveTempParserInterpreter(Grammar g, Parser originalParser, TokenStream tokens) {
+ ParserInterpreter parser;
+ if (originalParser instanceof ParserInterpreter) {
+ Class<? extends ParserInterpreter> c = originalParser.getClass().asSubclass(ParserInterpreter.class);
+ try {
+ Constructor<? extends ParserInterpreter> ctor = c.getConstructor(Grammar.class, ATN.class, TokenStream.class);
+ parser = ctor.newInstance(g, originalParser.getATN(), originalParser.getTokenStream());
+ }
+ catch (Exception e) {
+ throw new IllegalArgumentException("can't create parser to match incoming "+originalParser.getClass().getSimpleName(), e);
+ }
+ }
+ else { // must've been a generated parser
+ char[] serializedAtn = ATNSerializer.getSerializedAsChars(originalParser.getATN());
+ ATN deserialized = new ATNDeserializer().deserialize(serializedAtn);
+ parser = new ParserInterpreter(originalParser.getGrammarFileName(),
+ originalParser.getVocabulary(),
+ Arrays.asList(originalParser.getRuleNames()),
+ deserialized,
+ tokens);
+ }
+
+ parser.setInputStream(tokens);
+
+ // Make sure that we don't get any error messages from using this temporary parser
+ parser.setErrorHandler(new BailErrorStrategy());
+ parser.removeErrorListeners();
+ parser.removeParseListeners();
+ parser.getInterpreter().setPredictionMode(PredictionMode.LL_EXACT_AMBIG_DETECTION);
+ return parser;
+ }
+
+ /** We want to stop and track the first error but we cannot bail out like
+ * {@link BailErrorStrategy} as consume() constructs trees. We make sure
+ * to create an error node during recovery with this strategy. We
+ * consume() 1 token during the "bail out of rule" mechanism in recover()
+ * and let it fall out of the rule to finish constructing trees. For
+ * recovery in line, we throw InputMismatchException to engage recover().
+ */
+ public static class BailButConsumeErrorStrategy extends DefaultErrorStrategy {
+ public int firstErrorTokenIndex = -1;
+ @Override
+ public void recover(Parser recognizer, RecognitionException e) {
+ int errIndex = recognizer.getInputStream().index();
+ if ( firstErrorTokenIndex == -1 ) {
+ firstErrorTokenIndex = errIndex; // latch
+ }
+// System.err.println("recover: error at " + errIndex);
+ TokenStream input = recognizer.getInputStream();
+ if ( input.index()<input.size()-1 ) { // don't consume() eof
+ recognizer.consume(); // just kill this bad token and let it continue.
+ }
+ }
+
+ @Override
+ public Token recoverInline(Parser recognizer) throws RecognitionException {
+ int errIndex = recognizer.getInputStream().index();
+ if ( firstErrorTokenIndex == -1 ) {
+ firstErrorTokenIndex = errIndex; // latch
+ }
+// System.err.println("recoverInline: error at " + errIndex);
+ InputMismatchException e = new InputMismatchException(recognizer);
+// TokenStream input = recognizer.getInputStream(); // seek EOF
+// input.seek(input.size() - 1);
+ throw e;
+ }
+
+ @Override
+ public void sync(Parser recognizer) { } // don't consume anything; let it fail later
+ }
+}
diff --git a/tool/src/org/antlr/v4/tool/GrammarSemanticsMessage.java b/tool/src/org/antlr/v4/tool/GrammarSemanticsMessage.java
new file mode 100644
index 0000000..72e7501
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/GrammarSemanticsMessage.java
@@ -0,0 +1,52 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.tool;
+
+import org.antlr.runtime.Token;
+
+/** A problem with the symbols and/or meaning of a grammar such as rule
+ * redefinition. Any msg where we can point to a location in the grammar.
+ */
+public class GrammarSemanticsMessage extends ANTLRMessage {
+ public GrammarSemanticsMessage(ErrorType etype,
+ String fileName,
+ Token offendingToken,
+ Object... args)
+ {
+ super(etype,offendingToken,args);
+ this.fileName = fileName;
+ if ( offendingToken!=null ) {
+ line = offendingToken.getLine();
+ charPosition = offendingToken.getCharPositionInLine();
+ }
+ }
+}
+
diff --git a/tool/src/org/antlr/v4/tool/GrammarSyntaxMessage.java b/tool/src/org/antlr/v4/tool/GrammarSyntaxMessage.java
new file mode 100644
index 0000000..4648a84
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/GrammarSyntaxMessage.java
@@ -0,0 +1,60 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.tool;
+
+import org.antlr.runtime.RecognitionException;
+import org.antlr.runtime.Token;
+
+/** A problem with the syntax of your antlr grammar such as
+ * "The '{' came as a complete surprise to me at this point in your program"
+ */
+public class GrammarSyntaxMessage extends ANTLRMessage {
+ public GrammarSyntaxMessage(ErrorType etype,
+ String fileName,
+ Token offendingToken,
+ RecognitionException antlrException,
+ Object... args)
+ {
+ super(etype, antlrException, offendingToken, args);
+ this.fileName = fileName;
+ this.offendingToken = offendingToken;
+ if ( offendingToken!=null ) {
+ line = offendingToken.getLine();
+ charPosition = offendingToken.getCharPositionInLine();
+ }
+ }
+
+ @SuppressWarnings({"ThrowableResultOfMethodCallIgnored"})
+ @Override
+ public RecognitionException getCause() {
+ return (RecognitionException)super.getCause();
+ }
+}
diff --git a/tool/src/org/antlr/v4/tool/GrammarTransformPipeline.java b/tool/src/org/antlr/v4/tool/GrammarTransformPipeline.java
new file mode 100644
index 0000000..6759e20
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/GrammarTransformPipeline.java
@@ -0,0 +1,456 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.tool;
+
+import org.antlr.runtime.CommonToken;
+import org.antlr.runtime.tree.CommonTree;
+import org.antlr.runtime.tree.CommonTreeNodeStream;
+import org.antlr.runtime.tree.Tree;
+import org.antlr.runtime.tree.TreeVisitor;
+import org.antlr.runtime.tree.TreeVisitorAction;
+import org.antlr.v4.Tool;
+import org.antlr.v4.analysis.LeftRecursiveRuleTransformer;
+import org.antlr.v4.parse.ANTLRParser;
+import org.antlr.v4.parse.BlockSetTransformer;
+import org.antlr.v4.parse.GrammarASTAdaptor;
+import org.antlr.v4.parse.GrammarToken;
+import org.antlr.v4.runtime.misc.DoubleKeyMap;
+import org.antlr.v4.runtime.misc.Pair;
+import org.antlr.v4.tool.ast.AltAST;
+import org.antlr.v4.tool.ast.BlockAST;
+import org.antlr.v4.tool.ast.GrammarAST;
+import org.antlr.v4.tool.ast.GrammarASTWithOptions;
+import org.antlr.v4.tool.ast.GrammarRootAST;
+import org.antlr.v4.tool.ast.RuleAST;
+import org.antlr.v4.tool.ast.TerminalAST;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/** Handle left-recursion and block-set transforms */
+public class GrammarTransformPipeline {
+ public Grammar g;
+ public Tool tool;
+
+ public GrammarTransformPipeline(Grammar g, Tool tool) {
+ this.g = g;
+ this.tool = tool;
+ }
+
+ public void process() {
+ GrammarRootAST root = g.ast;
+ if ( root==null ) return;
+ tool.log("grammar", "before: "+root.toStringTree());
+
+ integrateImportedGrammars(g);
+ reduceBlocksToSets(root);
+ expandParameterizedLoops(root);
+
+ tool.log("grammar", "after: "+root.toStringTree());
+ }
+
+ public void reduceBlocksToSets(GrammarAST root) {
+ CommonTreeNodeStream nodes = new CommonTreeNodeStream(new GrammarASTAdaptor(), root);
+ GrammarASTAdaptor adaptor = new GrammarASTAdaptor();
+ BlockSetTransformer transformer = new BlockSetTransformer(nodes, g);
+ transformer.setTreeAdaptor(adaptor);
+ transformer.downup(root);
+ }
+
+ /** Find and replace
+ * ID*[','] with ID (',' ID)*
+ * ID+[','] with ID (',' ID)+
+ * (x {action} y)+[','] with x {action} y (',' x {action} y)+
+ *
+ * Parameter must be a token.
+ * todo: do we want?
+ */
+ public void expandParameterizedLoops(GrammarAST root) {
+ TreeVisitor v = new TreeVisitor(new GrammarASTAdaptor());
+ v.visit(root, new TreeVisitorAction() {
+ @Override
+ public Object pre(Object t) {
+ if ( ((GrammarAST)t).getType() == 3 ) {
+ return expandParameterizedLoop((GrammarAST)t);
+ }
+ return t;
+ }
+ @Override
+ public Object post(Object t) { return t; }
+ });
+ }
+
+ public GrammarAST expandParameterizedLoop(GrammarAST t) {
+ // todo: update grammar, alter AST
+ return t;
+ }
+
+ /** Utility visitor that sets grammar ptr in each node */
+ public static void setGrammarPtr(final Grammar g, GrammarAST tree) {
+ if ( tree==null ) return;
+ // ensure each node has pointer to surrounding grammar
+ TreeVisitor v = new TreeVisitor(new GrammarASTAdaptor());
+ v.visit(tree, new TreeVisitorAction() {
+ @Override
+ public Object pre(Object t) { ((GrammarAST)t).g = g; return t; }
+ @Override
+ public Object post(Object t) { return t; }
+ });
+ }
+
+ public static void augmentTokensWithOriginalPosition(final Grammar g, GrammarAST tree) {
+ if ( tree==null ) return;
+
+ List<GrammarAST> optionsSubTrees = tree.getNodesWithType(ANTLRParser.ELEMENT_OPTIONS);
+ for (int i = 0; i < optionsSubTrees.size(); i++) {
+ GrammarAST t = optionsSubTrees.get(i);
+ CommonTree elWithOpt = t.parent;
+ if ( elWithOpt instanceof GrammarASTWithOptions ) {
+ Map<String, GrammarAST> options = ((GrammarASTWithOptions) elWithOpt).getOptions();
+ if ( options.containsKey(LeftRecursiveRuleTransformer.TOKENINDEX_OPTION_NAME) ) {
+ GrammarToken newTok = new GrammarToken(g, elWithOpt.getToken());
+ newTok.originalTokenIndex = Integer.valueOf(options.get(LeftRecursiveRuleTransformer.TOKENINDEX_OPTION_NAME).getText());
+ elWithOpt.token = newTok;
+
+ GrammarAST originalNode = g.ast.getNodeWithTokenIndex(newTok.getTokenIndex());
+ if (originalNode != null) {
+ // update the AST node start/stop index to match the values
+ // of the corresponding node in the original parse tree.
+ elWithOpt.setTokenStartIndex(originalNode.getTokenStartIndex());
+ elWithOpt.setTokenStopIndex(originalNode.getTokenStopIndex());
+ }
+ else {
+ // the original AST node could not be located by index;
+ // make sure to assign valid values for the start/stop
+ // index so toTokenString will not throw exceptions.
+ elWithOpt.setTokenStartIndex(newTok.getTokenIndex());
+ elWithOpt.setTokenStopIndex(newTok.getTokenIndex());
+ }
+ }
+ }
+ }
+ }
+
+ /** Merge all the rules, token definitions, and named actions from
+ imported grammars into the root grammar tree. Perform:
+
+ (tokens { X (= Y 'y')) + (tokens { Z ) -> (tokens { X (= Y 'y') Z)
+
+ (@ members {foo}) + (@ members {bar}) -> (@ members {foobar})
+
+ (RULES (RULE x y)) + (RULES (RULE z)) -> (RULES (RULE x y z))
+
+ Rules in root prevent same rule from being appended to RULES node.
+
+ The goal is a complete combined grammar so we can ignore subordinate
+ grammars.
+ */
+ public void integrateImportedGrammars(Grammar rootGrammar) {
+ List<Grammar> imports = rootGrammar.getAllImportedGrammars();
+ if ( imports==null ) return;
+
+ GrammarAST root = rootGrammar.ast;
+ GrammarAST id = (GrammarAST) root.getChild(0);
+ GrammarASTAdaptor adaptor = new GrammarASTAdaptor(id.token.getInputStream());
+
+ GrammarAST tokensRoot = (GrammarAST)root.getFirstChildWithType(ANTLRParser.TOKENS_SPEC);
+
+ List<GrammarAST> actionRoots = root.getNodesWithType(ANTLRParser.AT);
+
+ // Compute list of rules in root grammar and ensure we have a RULES node
+ GrammarAST RULES = (GrammarAST)root.getFirstChildWithType(ANTLRParser.RULES);
+ Set<String> rootRuleNames = new HashSet<String>();
+ // make list of rules we have in root grammar
+ List<GrammarAST> rootRules = RULES.getNodesWithType(ANTLRParser.RULE);
+ for (GrammarAST r : rootRules) rootRuleNames.add(r.getChild(0).getText());
+
+ for (Grammar imp : imports) {
+ // COPY TOKENS
+ GrammarAST imp_tokensRoot = (GrammarAST)imp.ast.getFirstChildWithType(ANTLRParser.TOKENS_SPEC);
+ if ( imp_tokensRoot!=null ) {
+ rootGrammar.tool.log("grammar", "imported tokens: "+imp_tokensRoot.getChildren());
+ if ( tokensRoot==null ) {
+ tokensRoot = (GrammarAST)adaptor.create(ANTLRParser.TOKENS_SPEC, "TOKENS");
+ tokensRoot.g = rootGrammar;
+ root.insertChild(1, tokensRoot); // ^(GRAMMAR ID TOKENS...)
+ }
+ tokensRoot.addChildren(Arrays.asList(imp_tokensRoot.getChildren().toArray(new Tree[0])));
+ }
+
+ List<GrammarAST> all_actionRoots = new ArrayList<GrammarAST>();
+ List<GrammarAST> imp_actionRoots = imp.ast.getAllChildrenWithType(ANTLRParser.AT);
+ if ( actionRoots!=null ) all_actionRoots.addAll(actionRoots);
+ all_actionRoots.addAll(imp_actionRoots);
+
+ // COPY ACTIONS
+ if ( imp_actionRoots!=null ) {
+ DoubleKeyMap<String, String, GrammarAST> namedActions =
+ new DoubleKeyMap<String, String, GrammarAST>();
+
+ rootGrammar.tool.log("grammar", "imported actions: "+imp_actionRoots);
+ for (GrammarAST at : all_actionRoots) {
+ String scopeName = rootGrammar.getDefaultActionScope();
+ GrammarAST scope, name, action;
+ if ( at.getChildCount()>2 ) { // must have a scope
+ scope = (GrammarAST)at.getChild(0);
+ scopeName = scope.getText();
+ name = (GrammarAST)at.getChild(1);
+ action = (GrammarAST)at.getChild(2);
+ }
+ else {
+ name = (GrammarAST)at.getChild(0);
+ action = (GrammarAST)at.getChild(1);
+ }
+ GrammarAST prevAction = namedActions.get(scopeName, name.getText());
+ if ( prevAction==null ) {
+ namedActions.put(scopeName, name.getText(), action);
+ }
+ else {
+ if ( prevAction.g == at.g ) {
+ rootGrammar.tool.errMgr.grammarError(ErrorType.ACTION_REDEFINITION,
+ at.g.fileName, name.token, name.getText());
+ }
+ else {
+ String s1 = prevAction.getText();
+ s1 = s1.substring(1, s1.length()-1);
+ String s2 = action.getText();
+ s2 = s2.substring(1, s2.length()-1);
+ String combinedAction = "{"+s1 + '\n'+ s2+"}";
+ prevAction.token.setText(combinedAction);
+ }
+ }
+ }
+ // at this point, we have complete list of combined actions,
+ // some of which are already living in root grammar.
+ // Merge in any actions not in root grammar into root's tree.
+ for (String scopeName : namedActions.keySet()) {
+ for (String name : namedActions.keySet(scopeName)) {
+ GrammarAST action = namedActions.get(scopeName, name);
+ rootGrammar.tool.log("grammar", action.g.name+" "+scopeName+":"+name+"="+action.getText());
+ if ( action.g != rootGrammar ) {
+ root.insertChild(1, action.getParent());
+ }
+ }
+ }
+ }
+
+ // COPY RULES
+ List<GrammarAST> rules = imp.ast.getNodesWithType(ANTLRParser.RULE);
+ if ( rules!=null ) {
+ for (GrammarAST r : rules) {
+ rootGrammar.tool.log("grammar", "imported rule: "+r.toStringTree());
+ String name = r.getChild(0).getText();
+ boolean rootAlreadyHasRule = rootRuleNames.contains(name);
+ if ( !rootAlreadyHasRule ) {
+ RULES.addChild(r); // merge in if not overridden
+ rootRuleNames.add(name);
+ }
+ }
+ }
+
+ GrammarAST optionsRoot = (GrammarAST)imp.ast.getFirstChildWithType(ANTLRParser.OPTIONS);
+ if ( optionsRoot!=null ) {
+ // suppress the warning if the options match the options specified
+ // in the root grammar
+ // https://github.com/antlr/antlr4/issues/707
+
+ boolean hasNewOption = false;
+ for (Map.Entry<String, GrammarAST> option : imp.ast.getOptions().entrySet()) {
+ String importOption = imp.ast.getOptionString(option.getKey());
+ if (importOption == null) {
+ continue;
+ }
+
+ String rootOption = rootGrammar.ast.getOptionString(option.getKey());
+ if (!importOption.equals(rootOption)) {
+ hasNewOption = true;
+ break;
+ }
+ }
+
+ if (hasNewOption) {
+ rootGrammar.tool.errMgr.grammarError(ErrorType.OPTIONS_IN_DELEGATE,
+ optionsRoot.g.fileName, optionsRoot.token, imp.name);
+ }
+ }
+ }
+ rootGrammar.tool.log("grammar", "Grammar: "+rootGrammar.ast.toStringTree());
+ }
+
+ /** Build lexer grammar from combined grammar that looks like:
+ *
+ * (COMBINED_GRAMMAR A
+ * (tokens { X (= Y 'y'))
+ * (OPTIONS (= x 'y'))
+ * (@ members {foo})
+ * (@ lexer header {package jj;})
+ * (RULES (RULE .+)))
+ *
+ * Move rules and actions to new tree, don't dup. Split AST apart.
+ * We'll have this Grammar share token symbols later; don't generate
+ * tokenVocab or tokens{} section. Copy over named actions.
+ *
+ * Side-effects: it removes children from GRAMMAR & RULES nodes
+ * in combined AST. Anything cut out is dup'd before
+ * adding to lexer to avoid "who's ur daddy" issues
+ */
+ public GrammarRootAST extractImplicitLexer(Grammar combinedGrammar) {
+ GrammarRootAST combinedAST = combinedGrammar.ast;
+ //tool.log("grammar", "before="+combinedAST.toStringTree());
+ GrammarASTAdaptor adaptor = new GrammarASTAdaptor(combinedAST.token.getInputStream());
+ GrammarAST[] elements = combinedAST.getChildren().toArray(new GrammarAST[0]);
+
+ // MAKE A GRAMMAR ROOT and ID
+ String lexerName = combinedAST.getChild(0).getText()+"Lexer";
+ GrammarRootAST lexerAST =
+ new GrammarRootAST(new CommonToken(ANTLRParser.GRAMMAR, "LEXER_GRAMMAR"), combinedGrammar.ast.tokenStream);
+ lexerAST.grammarType = ANTLRParser.LEXER;
+ lexerAST.token.setInputStream(combinedAST.token.getInputStream());
+ lexerAST.addChild((GrammarAST)adaptor.create(ANTLRParser.ID, lexerName));
+
+ // COPY OPTIONS
+ GrammarAST optionsRoot =
+ (GrammarAST)combinedAST.getFirstChildWithType(ANTLRParser.OPTIONS);
+ if ( optionsRoot!=null && optionsRoot.getChildCount()!=0 ) {
+ GrammarAST lexerOptionsRoot = (GrammarAST)adaptor.dupNode(optionsRoot);
+ lexerAST.addChild(lexerOptionsRoot);
+ GrammarAST[] options = optionsRoot.getChildren().toArray(new GrammarAST[0]);
+ for (GrammarAST o : options) {
+ String optionName = o.getChild(0).getText();
+ if ( Grammar.lexerOptions.contains(optionName) &&
+ !Grammar.doNotCopyOptionsToLexer.contains(optionName) )
+ {
+ GrammarAST optionTree = (GrammarAST)adaptor.dupTree(o);
+ lexerOptionsRoot.addChild(optionTree);
+ lexerAST.setOption(optionName, (GrammarAST)optionTree.getChild(1));
+ }
+ }
+ }
+
+ // COPY all named actions, but only move those with lexer:: scope
+ List<GrammarAST> actionsWeMoved = new ArrayList<GrammarAST>();
+ for (GrammarAST e : elements) {
+ if ( e.getType()==ANTLRParser.AT ) {
+ lexerAST.addChild((Tree)adaptor.dupTree(e));
+ if ( e.getChild(0).getText().equals("lexer") ) {
+ actionsWeMoved.add(e);
+ }
+ }
+ }
+
+ for (GrammarAST r : actionsWeMoved) {
+ combinedAST.deleteChild( r );
+ }
+
+ GrammarAST combinedRulesRoot =
+ (GrammarAST)combinedAST.getFirstChildWithType(ANTLRParser.RULES);
+ if ( combinedRulesRoot==null ) return lexerAST;
+
+ // MOVE lexer rules
+
+ GrammarAST lexerRulesRoot =
+ (GrammarAST)adaptor.create(ANTLRParser.RULES, "RULES");
+ lexerAST.addChild(lexerRulesRoot);
+ List<GrammarAST> rulesWeMoved = new ArrayList<GrammarAST>();
+ GrammarASTWithOptions[] rules;
+ if (combinedRulesRoot.getChildCount() > 0) {
+ rules = combinedRulesRoot.getChildren().toArray(new GrammarASTWithOptions[0]);
+ }
+ else {
+ rules = new GrammarASTWithOptions[0];
+ }
+
+ for (GrammarASTWithOptions r : rules) {
+ String ruleName = r.getChild(0).getText();
+ if (Grammar.isTokenName(ruleName)) {
+ lexerRulesRoot.addChild((Tree)adaptor.dupTree(r));
+ rulesWeMoved.add(r);
+ }
+ }
+ for (GrammarAST r : rulesWeMoved) {
+ combinedRulesRoot.deleteChild( r );
+ }
+
+ // Will track 'if' from IF : 'if' ; rules to avoid defining new token for 'if'
+ List<Pair<GrammarAST,GrammarAST>> litAliases =
+ Grammar.getStringLiteralAliasesFromLexerRules(lexerAST);
+
+ Set<String> stringLiterals = combinedGrammar.getStringLiterals();
+ // add strings from combined grammar (and imported grammars) into lexer
+ // put them first as they are keywords; must resolve ambigs to these rules
+// tool.log("grammar", "strings from parser: "+stringLiterals);
+ int insertIndex = 0;
+ nextLit:
+ for (String lit : stringLiterals) {
+ // if lexer already has a rule for literal, continue
+ if ( litAliases!=null ) {
+ for (Pair<GrammarAST,GrammarAST> pair : litAliases) {
+ GrammarAST litAST = pair.b;
+ if ( lit.equals(litAST.getText()) ) continue nextLit;
+ }
+ }
+ // create for each literal: (RULE <uniquename> (BLOCK (ALT <lit>))
+ String rname = combinedGrammar.getStringLiteralLexerRuleName(lit);
+ // can't use wizard; need special node types
+ GrammarAST litRule = new RuleAST(ANTLRParser.RULE);
+ BlockAST blk = new BlockAST(ANTLRParser.BLOCK);
+ AltAST alt = new AltAST(ANTLRParser.ALT);
+ TerminalAST slit = new TerminalAST(new CommonToken(ANTLRParser.STRING_LITERAL, lit));
+ alt.addChild(slit);
+ blk.addChild(alt);
+ CommonToken idToken = new CommonToken(ANTLRParser.TOKEN_REF, rname);
+ litRule.addChild(new TerminalAST(idToken));
+ litRule.addChild(blk);
+ lexerRulesRoot.insertChild(insertIndex, litRule);
+// lexerRulesRoot.getChildren().add(0, litRule);
+ lexerRulesRoot.freshenParentAndChildIndexes(); // reset indexes and set litRule parent
+
+ // next literal will be added after the one just added
+ insertIndex++;
+ }
+
+ // TODO: take out after stable if slow
+ lexerAST.sanityCheckParentAndChildIndexes();
+ combinedAST.sanityCheckParentAndChildIndexes();
+// tool.log("grammar", combinedAST.toTokenString());
+
+ combinedGrammar.tool.log("grammar", "after extract implicit lexer ="+combinedAST.toStringTree());
+ combinedGrammar.tool.log("grammar", "lexer ="+lexerAST.toStringTree());
+
+ if ( lexerRulesRoot.getChildCount()==0 ) return null;
+ return lexerAST;
+ }
+
+}
diff --git a/tool/src/org/antlr/v4/tool/LabelElementPair.java b/tool/src/org/antlr/v4/tool/LabelElementPair.java
new file mode 100644
index 0000000..835bd5f
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/LabelElementPair.java
@@ -0,0 +1,74 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.tool;
+
+import org.antlr.runtime.BitSet;
+import org.antlr.v4.parse.ANTLRParser;
+import org.antlr.v4.tool.ast.GrammarAST;
+
+public class LabelElementPair {
+ public static final BitSet tokenTypeForTokens = new BitSet();
+ static {
+ tokenTypeForTokens.add(ANTLRParser.TOKEN_REF);
+ tokenTypeForTokens.add(ANTLRParser.STRING_LITERAL);
+ tokenTypeForTokens.add(ANTLRParser.WILDCARD);
+ }
+
+ public GrammarAST label;
+ public GrammarAST element;
+ public LabelType type;
+
+ public LabelElementPair(Grammar g, GrammarAST label, GrammarAST element, int labelOp) {
+ this.label = label;
+ this.element = element;
+ // compute general case for label type
+ if ( element.getFirstDescendantWithType(tokenTypeForTokens)!=null ) {
+ if ( labelOp==ANTLRParser.ASSIGN ) type = LabelType.TOKEN_LABEL;
+ else type = LabelType.TOKEN_LIST_LABEL;
+ }
+ else if ( element.getFirstDescendantWithType(ANTLRParser.RULE_REF)!=null ) {
+ if ( labelOp==ANTLRParser.ASSIGN ) type = LabelType.RULE_LABEL;
+ else type = LabelType.RULE_LIST_LABEL;
+ }
+
+ // now reset if lexer and string
+ if ( g.isLexer() ) {
+ if ( element.getFirstDescendantWithType(ANTLRParser.STRING_LITERAL)!=null ) {
+ if ( labelOp==ANTLRParser.ASSIGN ) type = LabelType.LEXER_STRING_LABEL;
+ }
+ }
+ }
+
+ @Override
+ public String toString() {
+ return label.getText()+" "+type+" "+element.toString();
+ }
+}
diff --git a/tool/src/org/antlr/v4/tool/LabelType.java b/tool/src/org/antlr/v4/tool/LabelType.java
new file mode 100644
index 0000000..df92ff9
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/LabelType.java
@@ -0,0 +1,45 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.tool;
+
+/** the various kinds of labels. t=type, id=ID, types+=type ids+=ID */
+public enum LabelType {
+ RULE_LABEL,
+ TOKEN_LABEL,
+ RULE_LIST_LABEL,
+ TOKEN_LIST_LABEL,
+ LEXER_STRING_LABEL, // used in lexer for x='a'
+ SUBRULE_LABEL, // x=(...)
+ SUBRULE_LIST_LABEL, // x+=(...)
+ WILDCARD_TREE_LABEL, // Used in tree grammar x=.
+ WILDCARD_TREE_LIST_LABEL // Used in tree grammar x+=.
+ ;
+}
diff --git a/tool/src/org/antlr/v4/tool/LeftRecursionCyclesMessage.java b/tool/src/org/antlr/v4/tool/LeftRecursionCyclesMessage.java
new file mode 100644
index 0000000..3e0740b
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/LeftRecursionCyclesMessage.java
@@ -0,0 +1,61 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.tool;
+
+import org.antlr.runtime.Token;
+
+import java.util.Collection;
+
+public class LeftRecursionCyclesMessage extends ANTLRMessage {
+ public LeftRecursionCyclesMessage(String fileName, Collection<? extends Collection<Rule>> cycles) {
+ super(ErrorType.LEFT_RECURSION_CYCLES, getStartTokenOfFirstRule(cycles), cycles);
+ this.fileName = fileName;
+ }
+
+ protected static Token getStartTokenOfFirstRule(Collection<? extends Collection<Rule>> cycles) {
+ if (cycles == null) {
+ return null;
+ }
+
+ for (Collection<Rule> collection : cycles) {
+ if (collection == null) {
+ return null;
+ }
+
+ for (Rule rule : collection) {
+ if (rule.ast != null) {
+ return rule.ast.getToken();
+ }
+ }
+ }
+ return null;
+ }
+}
diff --git a/tool/src/org/antlr/v4/tool/LeftRecursiveRule.java b/tool/src/org/antlr/v4/tool/LeftRecursiveRule.java
new file mode 100644
index 0000000..1d3b990
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/LeftRecursiveRule.java
@@ -0,0 +1,175 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.tool;
+
+import org.antlr.v4.analysis.LeftRecursiveRuleAltInfo;
+import org.antlr.v4.misc.OrderedHashMap;
+import org.antlr.v4.runtime.misc.Pair;
+import org.antlr.v4.tool.ast.AltAST;
+import org.antlr.v4.tool.ast.GrammarAST;
+import org.antlr.v4.tool.ast.RuleAST;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class LeftRecursiveRule extends Rule {
+ public List<LeftRecursiveRuleAltInfo> recPrimaryAlts;
+ public OrderedHashMap<Integer, LeftRecursiveRuleAltInfo> recOpAlts;
+ public RuleAST originalAST;
+
+ /** Did we delete any labels on direct left-recur refs? Points at ID of ^(= ID el) */
+ public List<Pair<GrammarAST,String>> leftRecursiveRuleRefLabels =
+ new ArrayList<Pair<GrammarAST,String>>();
+
+ public LeftRecursiveRule(Grammar g, String name, RuleAST ast) {
+ super(g, name, ast, 1);
+ originalAST = ast;
+ alt = new Alternative[numberOfAlts+1]; // always just one
+ for (int i=1; i<=numberOfAlts; i++) alt[i] = new Alternative(this, i);
+ }
+
+ @Override
+ public boolean hasAltSpecificContexts() {
+ return super.hasAltSpecificContexts() || getAltLabels()!=null;
+ }
+
+ @Override
+ public int getOriginalNumberOfAlts() {
+ int n = 0;
+ if ( recPrimaryAlts!=null ) n += recPrimaryAlts.size();
+ if ( recOpAlts!=null ) n += recOpAlts.size();
+ return n;
+ }
+
+ public RuleAST getOriginalAST() {
+ return originalAST;
+ }
+
+ @Override
+ public List<AltAST> getUnlabeledAltASTs() {
+ List<AltAST> alts = new ArrayList<AltAST>();
+ for (LeftRecursiveRuleAltInfo altInfo : recPrimaryAlts) {
+ if (altInfo.altLabel == null) alts.add(altInfo.originalAltAST);
+ }
+ for (int i = 0; i < recOpAlts.size(); i++) {
+ LeftRecursiveRuleAltInfo altInfo = recOpAlts.getElement(i);
+ if ( altInfo.altLabel==null ) alts.add(altInfo.originalAltAST);
+ }
+ if ( alts.isEmpty() ) return null;
+ return alts;
+ }
+
+ /** Return an array that maps predicted alt from primary decision
+ * to original alt of rule. For following rule, return [0, 2, 4]
+ *
+ e : e '*' e
+ | INT
+ | e '+' e
+ | ID
+ ;
+
+ * That maps predicted alt 1 to original alt 2 and predicted 2 to alt 4.
+ *
+ * @since 4.5.1
+ */
+ public int[] getPrimaryAlts() {
+ if ( recPrimaryAlts.size()==0 ) return null;
+ int[] alts = new int[recPrimaryAlts.size()+1];
+ for (int i = 0; i < recPrimaryAlts.size(); i++) { // recPrimaryAlts is a List not Map like recOpAlts
+ LeftRecursiveRuleAltInfo altInfo = recPrimaryAlts.get(i);
+ alts[i+1] = altInfo.altNum;
+ }
+ return alts;
+ }
+
+ /** Return an array that maps predicted alt from recursive op decision
+ * to original alt of rule. For following rule, return [0, 1, 3]
+ *
+ e : e '*' e
+ | INT
+ | e '+' e
+ | ID
+ ;
+
+ * That maps predicted alt 1 to original alt 1 and predicted 2 to alt 3.
+ *
+ * @since 4.5.1
+ */
+ public int[] getRecursiveOpAlts() {
+ if ( recOpAlts.size()==0 ) return null;
+ int[] alts = new int[recOpAlts.size()+1];
+ int alt = 1;
+ for (LeftRecursiveRuleAltInfo altInfo : recOpAlts.values()) {
+ alts[alt] = altInfo.altNum;
+ alt++; // recOpAlts has alts possibly with gaps
+ }
+ return alts;
+ }
+
+ /** Get -> labels from those alts we deleted for left-recursive rules. */
+ @Override
+ public Map<String, List<Pair<Integer, AltAST>>> getAltLabels() {
+ Map<String, List<Pair<Integer, AltAST>>> labels = new HashMap<String, List<Pair<Integer, AltAST>>>();
+ Map<String, List<Pair<Integer, AltAST>>> normalAltLabels = super.getAltLabels();
+ if ( normalAltLabels!=null ) labels.putAll(normalAltLabels);
+ if ( recPrimaryAlts!=null ) {
+ for (LeftRecursiveRuleAltInfo altInfo : recPrimaryAlts) {
+ if (altInfo.altLabel != null) {
+ List<Pair<Integer, AltAST>> pairs = labels.get(altInfo.altLabel);
+ if (pairs == null) {
+ pairs = new ArrayList<Pair<Integer, AltAST>>();
+ labels.put(altInfo.altLabel, pairs);
+ }
+
+ pairs.add(new Pair<Integer, AltAST>(altInfo.altNum, altInfo.originalAltAST));
+ }
+ }
+ }
+ if ( recOpAlts!=null ) {
+ for (int i = 0; i < recOpAlts.size(); i++) {
+ LeftRecursiveRuleAltInfo altInfo = recOpAlts.getElement(i);
+ if ( altInfo.altLabel!=null ) {
+ List<Pair<Integer, AltAST>> pairs = labels.get(altInfo.altLabel);
+ if (pairs == null) {
+ pairs = new ArrayList<Pair<Integer, AltAST>>();
+ labels.put(altInfo.altLabel, pairs);
+ }
+
+ pairs.add(new Pair<Integer, AltAST>(altInfo.altNum, altInfo.originalAltAST));
+ }
+ }
+ }
+ if ( labels.isEmpty() ) return null;
+ return labels;
+ }
+}
diff --git a/tool/src/org/antlr/v4/tool/LexerGrammar.java b/tool/src/org/antlr/v4/tool/LexerGrammar.java
new file mode 100644
index 0000000..5b92a80
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/LexerGrammar.java
@@ -0,0 +1,85 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.tool;
+
+import org.antlr.runtime.RecognitionException;
+import org.antlr.v4.Tool;
+import org.antlr.v4.runtime.misc.MultiMap;
+import org.antlr.v4.tool.ast.GrammarRootAST;
+
+/** */
+public class LexerGrammar extends Grammar {
+ public static final String DEFAULT_MODE_NAME = "DEFAULT_MODE";
+
+ /** The grammar from which this lexer grammar was derived (if implicit) */
+ public Grammar implicitLexerOwner;
+
+ /** DEFAULT_MODE rules are added first due to grammar syntax order */
+ public MultiMap<String, Rule> modes;
+
+ public LexerGrammar(Tool tool, GrammarRootAST ast) {
+ super(tool, ast);
+ }
+
+ public LexerGrammar(String grammarText) throws RecognitionException {
+ super(grammarText);
+ }
+
+ public LexerGrammar(String grammarText, ANTLRToolListener listener) throws RecognitionException {
+ super(grammarText, listener);
+ }
+
+ public LexerGrammar(String fileName, String grammarText, ANTLRToolListener listener) throws RecognitionException {
+ super(fileName, grammarText, listener);
+ }
+
+ @Override
+ public boolean defineRule(Rule r) {
+ if (!super.defineRule(r)) {
+ return false;
+ }
+
+ if ( modes==null ) modes = new MultiMap<String, Rule>();
+ modes.map(r.mode, r);
+ return true;
+ }
+
+ @Override
+ public boolean undefineRule(Rule r) {
+ if (!super.undefineRule(r)) {
+ return false;
+ }
+
+ boolean removed = modes.get(r.mode).remove(r);
+ assert removed;
+ return true;
+ }
+}
diff --git a/tool/src/org/antlr/v4/tool/Rule.java b/tool/src/org/antlr/v4/tool/Rule.java
new file mode 100644
index 0000000..38f5c88
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/Rule.java
@@ -0,0 +1,364 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.tool;
+
+import org.antlr.v4.runtime.misc.Pair;
+import org.antlr.v4.tool.ast.ActionAST;
+import org.antlr.v4.tool.ast.AltAST;
+import org.antlr.v4.tool.ast.GrammarAST;
+import org.antlr.v4.tool.ast.PredAST;
+import org.antlr.v4.tool.ast.RuleAST;
+import org.stringtemplate.v4.misc.MultiMap;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class Rule implements AttributeResolver {
+ /** Rule refs have a predefined set of attributes as well as
+ * the return values and args.
+ *
+ * These must be consistent with ActionTranslator.rulePropToModelMap, ...
+ */
+ public static final AttributeDict predefinedRulePropertiesDict =
+ new AttributeDict(AttributeDict.DictType.PREDEFINED_RULE);
+ static {
+ predefinedRulePropertiesDict.add(new Attribute("parser"));
+ predefinedRulePropertiesDict.add(new Attribute("text"));
+ predefinedRulePropertiesDict.add(new Attribute("start"));
+ predefinedRulePropertiesDict.add(new Attribute("stop"));
+ predefinedRulePropertiesDict.add(new Attribute("ctx"));
+ }
+
+ public static final Set<String> validLexerCommands = new HashSet<String>();
+ static {
+ // CALLS
+ validLexerCommands.add("mode");
+ validLexerCommands.add("pushMode");
+ validLexerCommands.add("type");
+ validLexerCommands.add("channel");
+
+ // ACTIONS
+ validLexerCommands.add("popMode");
+ validLexerCommands.add("skip");
+ validLexerCommands.add("more");
+ }
+
+ public String name;
+ public List<GrammarAST> modifiers;
+
+ public RuleAST ast;
+ public AttributeDict args;
+ public AttributeDict retvals;
+ public AttributeDict locals;
+
+ /** In which grammar does this rule live? */
+ public Grammar g;
+
+ /** If we're in a lexer grammar, we might be in a mode */
+ public String mode;
+
+ /** Map a name to an action for this rule like @init {...}.
+ * The code generator will use this to fill holes in the rule template.
+ * I track the AST node for the action in case I need the line number
+ * for errors.
+ */
+ public Map<String, ActionAST> namedActions =
+ new HashMap<String, ActionAST>();
+
+ /** Track exception handlers; points at "catch" node of (catch exception action)
+ * don't track finally action
+ */
+ public List<GrammarAST> exceptions = new ArrayList<GrammarAST>();
+
+ /** Track all executable actions other than named actions like @init
+ * and catch/finally (not in an alt). Also tracks predicates, rewrite actions.
+ * We need to examine these actions before code generation so
+ * that we can detect refs to $rule.attr etc...
+ *
+ * This tracks per rule; Alternative objs also track per alt.
+ */
+ public List<ActionAST> actions = new ArrayList<ActionAST>();
+
+ public ActionAST finallyAction;
+
+ public int numberOfAlts;
+
+ public boolean isStartRule = true; // nobody calls us
+
+ /** 1..n alts */
+ public Alternative[] alt;
+
+ /** All rules have unique index 0..n-1 */
+ public int index;
+
+ public int actionIndex = -1; // if lexer; 0..n-1 for n actions in a rule
+
+ public Rule(Grammar g, String name, RuleAST ast, int numberOfAlts) {
+ this.g = g;
+ this.name = name;
+ this.ast = ast;
+ this.numberOfAlts = numberOfAlts;
+ alt = new Alternative[numberOfAlts+1]; // 1..n
+ for (int i=1; i<=numberOfAlts; i++) alt[i] = new Alternative(this, i);
+ }
+
+ public void defineActionInAlt(int currentAlt, ActionAST actionAST) {
+ actions.add(actionAST);
+ alt[currentAlt].actions.add(actionAST);
+ if ( g.isLexer() ) {
+ defineLexerAction(actionAST);
+ }
+ }
+
+ /** Lexer actions are numbered across rules 0..n-1 */
+ public void defineLexerAction(ActionAST actionAST) {
+ actionIndex = g.lexerActions.size();
+ if ( g.lexerActions.get(actionAST)==null ) {
+ g.lexerActions.put(actionAST, actionIndex);
+ }
+ }
+
+ public void definePredicateInAlt(int currentAlt, PredAST predAST) {
+ actions.add(predAST);
+ alt[currentAlt].actions.add(predAST);
+ if ( g.sempreds.get(predAST)==null ) {
+ g.sempreds.put(predAST, g.sempreds.size());
+ }
+ }
+
+ public Attribute resolveRetvalOrProperty(String y) {
+ if ( retvals!=null ) {
+ Attribute a = retvals.get(y);
+ if ( a!=null ) return a;
+ }
+ AttributeDict d = getPredefinedScope(LabelType.RULE_LABEL);
+ return d.get(y);
+ }
+
+ public Set<String> getTokenRefs() {
+ Set<String> refs = new HashSet<String>();
+ for (int i=1; i<=numberOfAlts; i++) {
+ refs.addAll(alt[i].tokenRefs.keySet());
+ }
+ return refs;
+ }
+
+ public Set<String> getElementLabelNames() {
+ Set<String> refs = new HashSet<String>();
+ for (int i=1; i<=numberOfAlts; i++) {
+ refs.addAll(alt[i].labelDefs.keySet());
+ }
+ if ( refs.isEmpty() ) return null;
+ return refs;
+ }
+
+ public MultiMap<String, LabelElementPair> getElementLabelDefs() {
+ MultiMap<String, LabelElementPair> defs =
+ new MultiMap<String, LabelElementPair>();
+ for (int i=1; i<=numberOfAlts; i++) {
+ for (List<LabelElementPair> pairs : alt[i].labelDefs.values()) {
+ for (LabelElementPair p : pairs) {
+ defs.map(p.label.getText(), p);
+ }
+ }
+ }
+ return defs;
+ }
+
+ public boolean hasAltSpecificContexts() {
+ return getAltLabels()!=null;
+ }
+
+ /** Used for recursive rules (subclass), which have 1 alt, but many original alts */
+ public int getOriginalNumberOfAlts() {
+ return numberOfAlts;
+ }
+
+ /**
+ * Get {@code #} labels. The keys of the map are the labels applied to outer
+ * alternatives of a lexer rule, and the values are collections of pairs
+ * (alternative number and {@link AltAST}) identifying the alternatives with
+ * this label. Unlabeled alternatives are not included in the result.
+ */
+ public Map<String, List<Pair<Integer, AltAST>>> getAltLabels() {
+ Map<String, List<Pair<Integer, AltAST>>> labels = new LinkedHashMap<String, List<Pair<Integer, AltAST>>>();
+ for (int i=1; i<=numberOfAlts; i++) {
+ GrammarAST altLabel = alt[i].ast.altLabel;
+ if ( altLabel!=null ) {
+ List<Pair<Integer, AltAST>> list = labels.get(altLabel.getText());
+ if (list == null) {
+ list = new ArrayList<Pair<Integer, AltAST>>();
+ labels.put(altLabel.getText(), list);
+ }
+
+ list.add(new Pair<Integer, AltAST>(i, alt[i].ast));
+ }
+ }
+ if ( labels.isEmpty() ) return null;
+ return labels;
+ }
+
+ public List<AltAST> getUnlabeledAltASTs() {
+ List<AltAST> alts = new ArrayList<AltAST>();
+ for (int i=1; i<=numberOfAlts; i++) {
+ GrammarAST altLabel = alt[i].ast.altLabel;
+ if ( altLabel==null ) alts.add(alt[i].ast);
+ }
+ if ( alts.isEmpty() ) return null;
+ return alts;
+ }
+
+ /** $x Attribute: rule arguments, return values, predefined rule prop.
+ */
+ @Override
+ public Attribute resolveToAttribute(String x, ActionAST node) {
+ if ( args!=null ) {
+ Attribute a = args.get(x); if ( a!=null ) return a;
+ }
+ if ( retvals!=null ) {
+ Attribute a = retvals.get(x); if ( a!=null ) return a;
+ }
+ if ( locals!=null ) {
+ Attribute a = locals.get(x); if ( a!=null ) return a;
+ }
+ AttributeDict properties = getPredefinedScope(LabelType.RULE_LABEL);
+ return properties.get(x);
+ }
+
+ /** $x.y Attribute: x is surrounding rule, label ref (in any alts) */
+ @Override
+ public Attribute resolveToAttribute(String x, String y, ActionAST node) {
+ LabelElementPair anyLabelDef = getAnyLabelDef(x);
+ if ( anyLabelDef!=null ) {
+ if ( anyLabelDef.type==LabelType.RULE_LABEL ) {
+ return g.getRule(anyLabelDef.element.getText()).resolveRetvalOrProperty(y);
+ }
+ else {
+ AttributeDict scope = getPredefinedScope(anyLabelDef.type);
+ if (scope == null) {
+ return null;
+ }
+
+ return scope.get(y);
+ }
+ }
+ return null;
+
+ }
+
+ @Override
+ public boolean resolvesToLabel(String x, ActionAST node) {
+ LabelElementPair anyLabelDef = getAnyLabelDef(x);
+ return anyLabelDef!=null &&
+ (anyLabelDef.type==LabelType.RULE_LABEL ||
+ anyLabelDef.type==LabelType.TOKEN_LABEL);
+ }
+
+ @Override
+ public boolean resolvesToListLabel(String x, ActionAST node) {
+ LabelElementPair anyLabelDef = getAnyLabelDef(x);
+ return anyLabelDef!=null &&
+ (anyLabelDef.type==LabelType.RULE_LIST_LABEL ||
+ anyLabelDef.type==LabelType.TOKEN_LIST_LABEL);
+ }
+
+ @Override
+ public boolean resolvesToToken(String x, ActionAST node) {
+ LabelElementPair anyLabelDef = getAnyLabelDef(x);
+ if ( anyLabelDef!=null && anyLabelDef.type==LabelType.TOKEN_LABEL ) return true;
+ return false;
+ }
+
+ @Override
+ public boolean resolvesToAttributeDict(String x, ActionAST node) {
+ if ( resolvesToToken(x, node) ) return true;
+ return false;
+ }
+
+ public Rule resolveToRule(String x) {
+ if ( x.equals(this.name) ) return this;
+ LabelElementPair anyLabelDef = getAnyLabelDef(x);
+ if ( anyLabelDef!=null && anyLabelDef.type==LabelType.RULE_LABEL ) {
+ return g.getRule(anyLabelDef.element.getText());
+ }
+ return g.getRule(x);
+ }
+
+ public LabelElementPair getAnyLabelDef(String x) {
+ List<LabelElementPair> labels = getElementLabelDefs().get(x);
+ if ( labels!=null ) return labels.get(0);
+ return null;
+ }
+
+ public AttributeDict getPredefinedScope(LabelType ltype) {
+ String grammarLabelKey = g.getTypeString() + ":" + ltype;
+ return Grammar.grammarAndLabelRefTypeToScope.get(grammarLabelKey);
+ }
+
+ public boolean isFragment() {
+ if ( modifiers==null ) return false;
+ for (GrammarAST a : modifiers) {
+ if ( a.getText().equals("fragment") ) return true;
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() { return name.hashCode(); }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+
+ if (!(obj instanceof Rule)) {
+ return false;
+ }
+
+ return name.equals(((Rule)obj).name);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder buf = new StringBuilder();
+ buf.append("Rule{name=").append(name);
+ if ( args!=null ) buf.append(", args=").append(args);
+ if ( retvals!=null ) buf.append(", retvals=").append(retvals);
+ buf.append("}");
+ return buf.toString();
+ }
+}
diff --git a/tool/src/org/antlr/v4/tool/ToolMessage.java b/tool/src/org/antlr/v4/tool/ToolMessage.java
new file mode 100644
index 0000000..422eda2
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/ToolMessage.java
@@ -0,0 +1,53 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.tool;
+
+import org.antlr.runtime.Token;
+
+/** A generic message from the tool such as "file not found" type errors; there
+ * is no reason to create a special object for each error unlike the grammar
+ * errors, which may be rather complex.
+ *
+ * Sometimes you need to pass in a filename or something to say it is "bad".
+ * Allow a generic object to be passed in and the string template can deal
+ * with just printing it or pulling a property out of it.
+ */
+public class ToolMessage extends ANTLRMessage {
+ public ToolMessage(ErrorType errorType) {
+ super(errorType);
+ }
+ public ToolMessage(ErrorType errorType, Object... args) {
+ super(errorType, null, Token.INVALID_TOKEN, args);
+ }
+ public ToolMessage(ErrorType errorType, Throwable e, Object... args) {
+ super(errorType, e, Token.INVALID_TOKEN, args);
+ }
+}
diff --git a/tool/src/org/antlr/v4/tool/ast/ActionAST.java b/tool/src/org/antlr/v4/tool/ast/ActionAST.java
new file mode 100644
index 0000000..8daf349
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/ast/ActionAST.java
@@ -0,0 +1,58 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.tool.ast;
+
+import org.antlr.runtime.Token;
+import org.antlr.v4.tool.AttributeResolver;
+
+import java.util.List;
+
+public class ActionAST extends GrammarASTWithOptions implements RuleElementAST {
+ // Alt, rule, grammar space
+ public AttributeResolver resolver;
+ public List<Token> chunks; // useful for ANTLR IDE developers
+
+ public ActionAST(ActionAST node) {
+ super(node);
+ this.resolver = node.resolver;
+ this.chunks = node.chunks;
+ }
+
+ public ActionAST(Token t) { super(t); }
+ public ActionAST(int type) { super(type); }
+ public ActionAST(int type, Token t) { super(type, t); }
+
+ @Override
+ public ActionAST dupNode() { return new ActionAST(this); }
+
+ @Override
+ public Object visit(GrammarASTVisitor v) { return v.visit(this); }
+}
diff --git a/tool/src/org/antlr/v4/tool/ast/AltAST.java b/tool/src/org/antlr/v4/tool/ast/AltAST.java
new file mode 100644
index 0000000..77e2106
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/ast/AltAST.java
@@ -0,0 +1,66 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.tool.ast;
+
+import org.antlr.runtime.Token;
+import org.antlr.v4.analysis.LeftRecursiveRuleAltInfo;
+import org.antlr.v4.tool.Alternative;
+
+/** Any ALT (which can be child of ALT_REWRITE node) */
+public class AltAST extends GrammarASTWithOptions {
+ public Alternative alt;
+
+ /** If we transformed this alt from a left-recursive one, need info on it */
+ public LeftRecursiveRuleAltInfo leftRecursiveAltInfo;
+
+ /** If someone specified an outermost alternative label with #foo.
+ * Token type will be ID.
+ */
+ public GrammarAST altLabel;
+
+ public AltAST(AltAST node) {
+ super(node);
+ this.alt = node.alt;
+ this.altLabel = node.altLabel;
+ this.leftRecursiveAltInfo = node.leftRecursiveAltInfo;
+ }
+
+ public AltAST(Token t) { super(t); }
+ public AltAST(int type) { super(type); }
+ public AltAST(int type, Token t) { super(type, t); }
+ public AltAST(int type, Token t, String text) { super(type,t,text); }
+
+ @Override
+ public AltAST dupNode() { return new AltAST(this); }
+
+ @Override
+ public Object visit(GrammarASTVisitor v) { return v.visit(this); }
+}
diff --git a/tool/src/org/antlr/v4/tool/ast/BlockAST.java b/tool/src/org/antlr/v4/tool/ast/BlockAST.java
new file mode 100644
index 0000000..6e45e96
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/ast/BlockAST.java
@@ -0,0 +1,61 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.tool.ast;
+
+import org.antlr.runtime.Token;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class BlockAST extends GrammarASTWithOptions implements RuleElementAST {
+ // TODO: maybe I need a Subrule object like Rule so these options mov to that?
+ /** What are the default options for a subrule? */
+ public static final Map<String, String> defaultBlockOptions =
+ new HashMap<String, String>();
+
+ public static final Map<String, String> defaultLexerBlockOptions =
+ new HashMap<String, String>();
+
+ public BlockAST(BlockAST node) {
+ super(node);
+ }
+
+ public BlockAST(Token t) { super(t); }
+ public BlockAST(int type) { super(type); }
+ public BlockAST(int type, Token t) { super(type, t); }
+ public BlockAST(int type, Token t, String text) { super(type,t,text); }
+
+ @Override
+ public BlockAST dupNode() { return new BlockAST(this); }
+
+ @Override
+ public Object visit(GrammarASTVisitor v) { return v.visit(this); }
+}
diff --git a/tool/src/org/antlr/v4/tool/ast/GrammarAST.java b/tool/src/org/antlr/v4/tool/ast/GrammarAST.java
new file mode 100644
index 0000000..a794b88
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/ast/GrammarAST.java
@@ -0,0 +1,264 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.tool.ast;
+
+import org.antlr.runtime.CharStream;
+import org.antlr.runtime.CommonToken;
+import org.antlr.runtime.Token;
+import org.antlr.runtime.tree.CommonTree;
+import org.antlr.runtime.tree.CommonTreeNodeStream;
+import org.antlr.runtime.tree.Tree;
+import org.antlr.v4.parse.ANTLRParser;
+import org.antlr.v4.parse.GrammarASTAdaptor;
+import org.antlr.v4.runtime.atn.ATNState;
+import org.antlr.v4.runtime.misc.IntervalSet;
+import org.antlr.v4.tool.Grammar;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+
+public class GrammarAST extends CommonTree {
+ /** For error msgs, nice to know which grammar this AST lives in */
+ // TODO: try to remove
+ public Grammar g;
+
+ /** If we build an ATN, we make AST node point at left edge of ATN construct */
+ public ATNState atnState;
+
+ public String textOverride;
+
+ public GrammarAST() {}
+ public GrammarAST(Token t) { super(t); }
+ public GrammarAST(GrammarAST node) {
+ super(node);
+ this.g = node.g;
+ this.atnState = node.atnState;
+ this.textOverride = node.textOverride;
+ }
+ public GrammarAST(int type) { super(new CommonToken(type, ANTLRParser.tokenNames[type])); }
+ public GrammarAST(int type, Token t) {
+ this(new CommonToken(t));
+ token.setType(type);
+ }
+ public GrammarAST(int type, Token t, String text) {
+ this(new CommonToken(t));
+ token.setType(type);
+ token.setText(text);
+ }
+
+ public GrammarAST[] getChildrenAsArray() {
+ return children.toArray(new GrammarAST[children.size()]);
+ }
+
+ public List<GrammarAST> getNodesWithType(int ttype) {
+ return getNodesWithType(IntervalSet.of(ttype));
+ }
+
+ public List<GrammarAST> getAllChildrenWithType(int type) {
+ List<GrammarAST> nodes = new ArrayList<GrammarAST>();
+ for (int i = 0; children!=null && i < children.size(); i++) {
+ Tree t = (Tree) children.get(i);
+ if ( t.getType()==type ) {
+ nodes.add((GrammarAST)t);
+ }
+ }
+ return nodes;
+ }
+
+ public List<GrammarAST> getNodesWithType(IntervalSet types) {
+ List<GrammarAST> nodes = new ArrayList<GrammarAST>();
+ List<GrammarAST> work = new LinkedList<GrammarAST>();
+ work.add(this);
+ GrammarAST t;
+ while ( !work.isEmpty() ) {
+ t = work.remove(0);
+ if ( types==null || types.contains(t.getType()) ) nodes.add(t);
+ if ( t.children!=null ) {
+ work.addAll(Arrays.asList(t.getChildrenAsArray()));
+ }
+ }
+ return nodes;
+ }
+
+ public List<GrammarAST> getNodesWithTypePreorderDFS(IntervalSet types) {
+ ArrayList<GrammarAST> nodes = new ArrayList<GrammarAST>();
+ getNodesWithTypePreorderDFS_(nodes, types);
+ return nodes;
+ }
+
+ public void getNodesWithTypePreorderDFS_(List<GrammarAST> nodes, IntervalSet types) {
+ if ( types.contains(this.getType()) ) nodes.add(this);
+ // walk all children of root.
+ for (int i= 0; i < getChildCount(); i++) {
+ GrammarAST child = (GrammarAST)getChild(i);
+ child.getNodesWithTypePreorderDFS_(nodes, types);
+ }
+ }
+
+ public GrammarAST getNodeWithTokenIndex(int index) {
+ if ( this.getToken()!=null && this.getToken().getTokenIndex()==index ) {
+ return this;
+ }
+ // walk all children of root.
+ for (int i= 0; i < getChildCount(); i++) {
+ GrammarAST child = (GrammarAST)getChild(i);
+ GrammarAST result = child.getNodeWithTokenIndex(index);
+ if ( result!=null ) {
+ return result;
+ }
+ }
+ return null;
+ }
+
+ public AltAST getOutermostAltNode() {
+ if ( this instanceof AltAST && parent.parent instanceof RuleAST ) {
+ return (AltAST)this;
+ }
+ if ( parent!=null ) return ((GrammarAST)parent).getOutermostAltNode();
+ return null;
+ }
+
+ /** Walk ancestors of this node until we find ALT with
+ * alt!=null or leftRecursiveAltInfo!=null. Then grab label if any.
+ * If not a rule element, just returns null.
+ */
+ public String getAltLabel() {
+ List<? extends Tree> ancestors = this.getAncestors();
+ if ( ancestors==null ) return null;
+ for (int i=ancestors.size()-1; i>=0; i--) {
+ GrammarAST p = (GrammarAST)ancestors.get(i);
+ if ( p.getType()== ANTLRParser.ALT ) {
+ AltAST a = (AltAST)p;
+ if ( a.altLabel!=null ) return a.altLabel.getText();
+ if ( a.leftRecursiveAltInfo!=null ) {
+ return a.leftRecursiveAltInfo.altLabel;
+ }
+ }
+ }
+ return null;
+ }
+
+ public boolean deleteChild(org.antlr.runtime.tree.Tree t) {
+ for (int i=0; i<children.size(); i++) {
+ Object c = children.get(i);
+ if ( c == t ) {
+ deleteChild(t.getChildIndex());
+ return true;
+ }
+ }
+ return false;
+ }
+
+ // TODO: move to basetree when i settle on how runtime works
+ // TODO: don't include this node!!
+ // TODO: reuse other method
+ public CommonTree getFirstDescendantWithType(int type) {
+ if ( getType()==type ) return this;
+ if ( children==null ) return null;
+ for (Object c : children) {
+ GrammarAST t = (GrammarAST)c;
+ if ( t.getType()==type ) return t;
+ CommonTree d = t.getFirstDescendantWithType(type);
+ if ( d!=null ) return d;
+ }
+ return null;
+ }
+
+ // TODO: don't include this node!!
+ public CommonTree getFirstDescendantWithType(org.antlr.runtime.BitSet types) {
+ if ( types.member(getType()) ) return this;
+ if ( children==null ) return null;
+ for (Object c : children) {
+ GrammarAST t = (GrammarAST)c;
+ if ( types.member(t.getType()) ) return t;
+ CommonTree d = t.getFirstDescendantWithType(types);
+ if ( d!=null ) return d;
+ }
+ return null;
+ }
+
+ public void setType(int type) {
+ token.setType(type);
+ }
+//
+// @Override
+// public String getText() {
+// if ( textOverride!=null ) return textOverride;
+// if ( token!=null ) {
+// return token.getText();
+// }
+// return "";
+// }
+
+ public void setText(String text) {
+// textOverride = text; // don't alt tokens as others might see
+ token.setText(text); // we delete surrounding tree, so ok to alter
+ }
+
+// @Override
+// public boolean equals(Object obj) {
+// return super.equals(obj);
+// }
+
+ @Override
+ public GrammarAST dupNode() {
+ return new GrammarAST(this);
+ }
+
+ public GrammarAST dupTree() {
+ GrammarAST t = this;
+ CharStream input = this.token.getInputStream();
+ GrammarASTAdaptor adaptor = new GrammarASTAdaptor(input);
+ return (GrammarAST)adaptor.dupTree(t);
+ }
+
+ public String toTokenString() {
+ CharStream input = this.token.getInputStream();
+ GrammarASTAdaptor adaptor = new GrammarASTAdaptor(input);
+ CommonTreeNodeStream nodes =
+ new CommonTreeNodeStream(adaptor, this);
+ StringBuilder buf = new StringBuilder();
+ GrammarAST o = (GrammarAST)nodes.LT(1);
+ int type = adaptor.getType(o);
+ while ( type!=Token.EOF ) {
+ buf.append(" ");
+ buf.append(o.getText());
+ nodes.consume();
+ o = (GrammarAST)nodes.LT(1);
+ type = adaptor.getType(o);
+ }
+ return buf.toString();
+ }
+
+ public Object visit(GrammarASTVisitor v) { return v.visit(this); }
+}
diff --git a/tool/src/org/antlr/v4/tool/ast/GrammarASTErrorNode.java b/tool/src/org/antlr/v4/tool/ast/GrammarASTErrorNode.java
new file mode 100644
index 0000000..3b2094b
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/ast/GrammarASTErrorNode.java
@@ -0,0 +1,56 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.tool.ast;
+
+import org.antlr.runtime.Token;
+import org.antlr.runtime.TokenStream;
+import org.antlr.runtime.tree.CommonErrorNode;
+
+/** A node representing erroneous token range in token stream */
+public class GrammarASTErrorNode extends GrammarAST {
+ CommonErrorNode delegate;
+ public GrammarASTErrorNode(TokenStream input, Token start, Token stop,
+ org.antlr.runtime.RecognitionException e)
+ {
+ delegate = new CommonErrorNode(input,start,stop,e);
+ }
+
+ @Override
+ public boolean isNil() { return delegate.isNil(); }
+
+ @Override
+ public int getType() { return delegate.getType(); }
+
+ @Override
+ public String getText() { return delegate.getText(); }
+ @Override
+ public String toString() { return delegate.toString(); }
+}
diff --git a/tool/src/org/antlr/v4/tool/ast/GrammarASTVisitor.java b/tool/src/org/antlr/v4/tool/ast/GrammarASTVisitor.java
new file mode 100644
index 0000000..a11deb1
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/ast/GrammarASTVisitor.java
@@ -0,0 +1,68 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.tool.ast;
+
+/** A simple visitor, based upon the classic double dispatch method,
+ * for walking GrammarAST trees resulting from parsing ANTLR grammars.
+ * There is also the GrammarTreeVisitor.g tree grammar that looks for
+ * subtree patterns and fires off high-level events as opposed to
+ * "found node" events like this visitor does. Also, like all
+ * visitors, the users of this interface are required to implement
+ * the node visitation of the children. The GrammarTreeVisitor mechanism
+ * fires events and the user is not required to do any walking code.
+ *
+ * GrammarAST t = ...;
+ * GrammarASTVisitor v = new ...;
+ * t.visit(v);
+ */
+public interface GrammarASTVisitor {
+ /** This is the generic visitor method that will be invoked
+ * for any other kind of AST node not covered by the other visit methods.
+ */
+ Object visit(GrammarAST node);
+
+ Object visit(GrammarRootAST node);
+ Object visit(RuleAST node);
+
+ Object visit(BlockAST node);
+ Object visit(OptionalBlockAST node);
+ Object visit(PlusBlockAST node);
+ Object visit(StarBlockAST node);
+
+ Object visit(AltAST node);
+
+ Object visit(NotAST node);
+ Object visit(PredAST node);
+ Object visit(RangeAST node);
+ Object visit(SetAST node);
+ Object visit(RuleRefAST node);
+ Object visit(TerminalAST node);
+}
diff --git a/tool/src/org/antlr/v4/tool/ast/GrammarASTWithOptions.java b/tool/src/org/antlr/v4/tool/ast/GrammarASTWithOptions.java
new file mode 100644
index 0000000..b492c93
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/ast/GrammarASTWithOptions.java
@@ -0,0 +1,96 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.tool.ast;
+
+import org.antlr.runtime.Token;
+import org.antlr.v4.misc.CharSupport;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+public abstract class GrammarASTWithOptions extends GrammarAST {
+ protected Map<String, GrammarAST> options;
+
+ public GrammarASTWithOptions(GrammarASTWithOptions node) {
+ super(node);
+ this.options = node.options;
+ }
+
+ public GrammarASTWithOptions(Token t) { super(t); }
+ public GrammarASTWithOptions(int type) { super(type); }
+ public GrammarASTWithOptions(int type, Token t) { super(type, t); }
+ public GrammarASTWithOptions(int type, Token t, String text) { super(type,t,text); }
+
+ public void setOption(String key, GrammarAST node) {
+ if ( options==null ) options = new HashMap<String, GrammarAST>();
+ options.put(key, node);
+ }
+
+ public String getOptionString(String key) {
+ GrammarAST value = getOptionAST(key);
+ if ( value == null ) return null;
+ if ( value instanceof ActionAST ) {
+ return value.getText();
+ }
+ else {
+ String v = value.getText();
+ if ( v.startsWith("'") || v.startsWith("\"") ) {
+ v = CharSupport.getStringFromGrammarStringLiteral(v);
+ }
+ return v;
+ }
+ }
+
+ /** Gets AST node holding value for option key; ignores default options
+ * and command-line forced options.
+ */
+ public GrammarAST getOptionAST(String key) {
+ if ( options==null ) return null;
+ return options.get(key);
+ }
+
+ public int getNumberOfOptions() {
+ return options==null ? 0 : options.size();
+ }
+
+ @Override
+ public abstract GrammarASTWithOptions dupNode();
+
+
+ public Map<String, GrammarAST> getOptions() {
+ if (options == null) {
+ return Collections.emptyMap();
+ }
+
+ return options;
+ }
+}
diff --git a/tool/src/org/antlr/v4/tool/ast/GrammarRootAST.java b/tool/src/org/antlr/v4/tool/ast/GrammarRootAST.java
new file mode 100644
index 0000000..bf4ef96
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/ast/GrammarRootAST.java
@@ -0,0 +1,111 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.tool.ast;
+
+import org.antlr.runtime.Token;
+import org.antlr.runtime.TokenStream;
+import org.antlr.runtime.tree.Tree;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class GrammarRootAST extends GrammarASTWithOptions {
+ public static final Map<String, String> defaultOptions = new HashMap<String, String>();
+ static {
+ defaultOptions.put("language","Java");
+ }
+
+ public int grammarType; // LEXER, PARSER, GRAMMAR (combined)
+ public boolean hasErrors;
+ /** Track stream used to create this tree */
+
+ public final TokenStream tokenStream;
+ public Map<String, String> cmdLineOptions; // -DsuperClass=T on command line
+ public String fileName;
+
+ public GrammarRootAST(GrammarRootAST node) {
+ super(node);
+ this.grammarType = node.grammarType;
+ this.hasErrors = node.hasErrors;
+ this.tokenStream = node.tokenStream;
+ }
+
+ public GrammarRootAST(Token t, TokenStream tokenStream) {
+ super(t);
+ if (tokenStream == null) {
+ throw new NullPointerException("tokenStream");
+ }
+
+ this.tokenStream = tokenStream;
+ }
+
+ public GrammarRootAST(int type, Token t, TokenStream tokenStream) {
+ super(type, t);
+ if (tokenStream == null) {
+ throw new NullPointerException("tokenStream");
+ }
+
+ this.tokenStream = tokenStream;
+ }
+
+ public GrammarRootAST(int type, Token t, String text, TokenStream tokenStream) {
+ super(type,t,text);
+ if (tokenStream == null) {
+ throw new NullPointerException("tokenStream");
+ }
+
+ this.tokenStream = tokenStream;
+ }
+
+ public String getGrammarName() {
+ Tree t = getChild(0);
+ if ( t!=null ) return t.getText();
+ return null;
+ }
+
+ @Override
+ public String getOptionString(String key) {
+ if ( cmdLineOptions!=null && cmdLineOptions.containsKey(key) ) {
+ return cmdLineOptions.get(key);
+ }
+ String value = super.getOptionString(key);
+ if ( value==null ) {
+ value = defaultOptions.get(key);
+ }
+ return value;
+ }
+
+ @Override
+ public Object visit(GrammarASTVisitor v) { return v.visit(this); }
+
+ @Override
+ public GrammarRootAST dupNode() { return new GrammarRootAST(this); }
+}
diff --git a/tool/src/org/antlr/v4/tool/ast/NotAST.java b/tool/src/org/antlr/v4/tool/ast/NotAST.java
new file mode 100644
index 0000000..0d943e6
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/ast/NotAST.java
@@ -0,0 +1,50 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.tool.ast;
+
+import org.antlr.runtime.Token;
+
+public class NotAST extends GrammarAST implements RuleElementAST {
+
+ public NotAST(NotAST node) {
+ super(node);
+ }
+
+ public NotAST(int type, Token t) { super(type, t); }
+
+ @Override
+ public NotAST dupNode() {
+ return new NotAST(this);
+ }
+
+ @Override
+ public Object visit(GrammarASTVisitor v) { return v.visit(this); }
+}
diff --git a/tool/src/org/antlr/v4/tool/ast/OptionalBlockAST.java b/tool/src/org/antlr/v4/tool/ast/OptionalBlockAST.java
new file mode 100644
index 0000000..fafdfc3
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/ast/OptionalBlockAST.java
@@ -0,0 +1,59 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.tool.ast;
+
+import org.antlr.runtime.Token;
+
+public class OptionalBlockAST extends GrammarAST implements RuleElementAST, QuantifierAST {
+ private final boolean _greedy;
+
+ public OptionalBlockAST(OptionalBlockAST node) {
+ super(node);
+ _greedy = node._greedy;
+ }
+
+ public OptionalBlockAST(int type, Token t, Token nongreedy) {
+ super(type, t);
+ _greedy = nongreedy == null;
+ }
+
+ @Override
+ public boolean isGreedy() {
+ return _greedy;
+ }
+
+ @Override
+ public OptionalBlockAST dupNode() { return new OptionalBlockAST(this); }
+
+ @Override
+ public Object visit(GrammarASTVisitor v) { return v.visit(this); }
+
+}
diff --git a/tool/src/org/antlr/v4/tool/ast/PlusBlockAST.java b/tool/src/org/antlr/v4/tool/ast/PlusBlockAST.java
new file mode 100644
index 0000000..2bd97be
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/ast/PlusBlockAST.java
@@ -0,0 +1,58 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.tool.ast;
+
+import org.antlr.runtime.Token;
+
+public class PlusBlockAST extends GrammarAST implements RuleElementAST, QuantifierAST {
+ private final boolean _greedy;
+
+ public PlusBlockAST(PlusBlockAST node) {
+ super(node);
+ _greedy = node._greedy;
+ }
+
+ public PlusBlockAST(int type, Token t, Token nongreedy) {
+ super(type, t);
+ _greedy = nongreedy == null;
+ }
+
+ @Override
+ public boolean isGreedy() {
+ return _greedy;
+ }
+
+ @Override
+ public PlusBlockAST dupNode() { return new PlusBlockAST(this); }
+
+ @Override
+ public Object visit(GrammarASTVisitor v) { return v.visit(this); }
+}
diff --git a/tool/src/org/antlr/v4/tool/ast/PredAST.java b/tool/src/org/antlr/v4/tool/ast/PredAST.java
new file mode 100644
index 0000000..c7d0706
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/ast/PredAST.java
@@ -0,0 +1,49 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.tool.ast;
+
+import org.antlr.runtime.Token;
+
+public class PredAST extends ActionAST {
+ public PredAST(PredAST node) {
+ super(node);
+ }
+
+ public PredAST(Token t) { super(t); }
+ public PredAST(int type) { super(type); }
+ public PredAST(int type, Token t) { super(type, t); }
+
+ @Override
+ public PredAST dupNode() { return new PredAST(this); }
+
+ @Override
+ public Object visit(GrammarASTVisitor v) { return v.visit(this); }
+}
diff --git a/tool/src/org/antlr/v4/tool/ast/QuantifierAST.java b/tool/src/org/antlr/v4/tool/ast/QuantifierAST.java
new file mode 100644
index 0000000..0869ca7
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/ast/QuantifierAST.java
@@ -0,0 +1,41 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.tool.ast;
+
+/**
+ *
+ * @author Sam Harwell
+ */
+public interface QuantifierAST {
+
+ boolean isGreedy();
+
+}
diff --git a/tool/src/org/antlr/v4/tool/ast/RangeAST.java b/tool/src/org/antlr/v4/tool/ast/RangeAST.java
new file mode 100644
index 0000000..54ce96a
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/ast/RangeAST.java
@@ -0,0 +1,50 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.tool.ast;
+
+import org.antlr.runtime.Token;
+
+public class RangeAST extends GrammarAST implements RuleElementAST {
+
+ public RangeAST(RangeAST node) {
+ super(node);
+ }
+
+ public RangeAST(Token t) { super(t); }
+
+ @Override
+ public RangeAST dupNode() {
+ return new RangeAST(this);
+ }
+
+ @Override
+ public Object visit(GrammarASTVisitor v) { return v.visit(this); }
+}
diff --git a/tool/src/org/antlr/v4/tool/ast/RuleAST.java b/tool/src/org/antlr/v4/tool/ast/RuleAST.java
new file mode 100644
index 0000000..0db780a
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/ast/RuleAST.java
@@ -0,0 +1,74 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.tool.ast;
+
+import org.antlr.runtime.Token;
+import org.antlr.runtime.tree.Tree;
+import org.antlr.v4.parse.ANTLRParser;
+import org.antlr.v4.tool.Grammar;
+
+public class RuleAST extends GrammarASTWithOptions {
+ public RuleAST(RuleAST node) {
+ super(node);
+ }
+
+ public RuleAST(Token t) { super(t); }
+ public RuleAST(int type) { super(type); }
+
+ public boolean isLexerRule() {
+ String name = getRuleName();
+ return name!=null && Grammar.isTokenName(name);
+ }
+
+ public String getRuleName() {
+ GrammarAST nameNode = (GrammarAST)getChild(0);
+ if ( nameNode!=null ) return nameNode.getText();
+ return null;
+ }
+
+ @Override
+ public RuleAST dupNode() { return new RuleAST(this); }
+
+ public ActionAST getLexerAction() {
+ Tree blk = getFirstChildWithType(ANTLRParser.BLOCK);
+ if ( blk.getChildCount()==1 ) {
+ Tree onlyAlt = blk.getChild(0);
+ Tree lastChild = onlyAlt.getChild(onlyAlt.getChildCount()-1);
+ if ( lastChild.getType()==ANTLRParser.ACTION ) {
+ return (ActionAST)lastChild;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public Object visit(GrammarASTVisitor v) { return v.visit(this); }
+}
diff --git a/tool/src/org/antlr/v4/tool/ast/RuleElementAST.java b/tool/src/org/antlr/v4/tool/ast/RuleElementAST.java
new file mode 100644
index 0000000..e5118fa
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/ast/RuleElementAST.java
@@ -0,0 +1,35 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.tool.ast;
+
+/** Tag indicated AST node is a rule element like token or rule ref. */
+public interface RuleElementAST {
+}
diff --git a/tool/src/org/antlr/v4/tool/ast/RuleRefAST.java b/tool/src/org/antlr/v4/tool/ast/RuleRefAST.java
new file mode 100644
index 0000000..822c142
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/ast/RuleRefAST.java
@@ -0,0 +1,60 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.tool.ast;
+
+import org.antlr.runtime.CommonToken;
+import org.antlr.runtime.Token;
+
+public class RuleRefAST extends GrammarASTWithOptions implements RuleElementAST {
+ public RuleRefAST(RuleRefAST node) {
+ super(node);
+ }
+
+ public RuleRefAST(Token t) { super(t); }
+ public RuleRefAST(int type) { super(type); }
+ public RuleRefAST(int type, Token t) { super(type, t); }
+
+ /** Dup token too since we overwrite during LR rule transform */
+ @Override
+ public RuleRefAST dupNode() {
+ RuleRefAST r = new RuleRefAST(this);
+ // In LR transform, we alter original token stream to make e -> e[n]
+ // Since we will be altering the dup, we need dup to have the
+ // original token. We can set this tree (the original) to have
+ // a new token.
+ r.token = this.token;
+ this.token = new CommonToken(r.token);
+ return r;
+ }
+
+ @Override
+ public Object visit(GrammarASTVisitor v) { return v.visit(this); }
+}
diff --git a/tool/src/org/antlr/v4/tool/ast/SetAST.java b/tool/src/org/antlr/v4/tool/ast/SetAST.java
new file mode 100644
index 0000000..9c06b49
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/ast/SetAST.java
@@ -0,0 +1,50 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.tool.ast;
+
+import org.antlr.runtime.Token;
+
+public class SetAST extends GrammarAST implements RuleElementAST {
+
+ public SetAST(SetAST node) {
+ super(node);
+ }
+
+ public SetAST(int type, Token t, String text) { super(type,t,text); }
+
+ @Override
+ public SetAST dupNode() {
+ return new SetAST(this);
+ }
+
+ @Override
+ public Object visit(GrammarASTVisitor v) { return v.visit(this); }
+}
diff --git a/tool/src/org/antlr/v4/tool/ast/StarBlockAST.java b/tool/src/org/antlr/v4/tool/ast/StarBlockAST.java
new file mode 100644
index 0000000..58c7b45
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/ast/StarBlockAST.java
@@ -0,0 +1,58 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.tool.ast;
+
+import org.antlr.runtime.Token;
+
+public class StarBlockAST extends GrammarAST implements RuleElementAST, QuantifierAST {
+ private final boolean _greedy;
+
+ public StarBlockAST(StarBlockAST node) {
+ super(node);
+ _greedy = node._greedy;
+ }
+
+ public StarBlockAST(int type, Token t, Token nongreedy) {
+ super(type, t);
+ _greedy = nongreedy == null;
+ }
+
+ @Override
+ public boolean isGreedy() {
+ return _greedy;
+ }
+
+ @Override
+ public StarBlockAST dupNode() { return new StarBlockAST(this); }
+
+ @Override
+ public Object visit(GrammarASTVisitor v) { return v.visit(this); }
+}
diff --git a/tool/src/org/antlr/v4/tool/ast/TerminalAST.java b/tool/src/org/antlr/v4/tool/ast/TerminalAST.java
new file mode 100644
index 0000000..26114f3
--- /dev/null
+++ b/tool/src/org/antlr/v4/tool/ast/TerminalAST.java
@@ -0,0 +1,50 @@
+/*
+ * [The "BSD license"]
+ * Copyright (c) 2012 Terence Parr
+ * Copyright (c) 2012 Sam Harwell
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.antlr.v4.tool.ast;
+
+import org.antlr.runtime.Token;
+
+public class TerminalAST extends GrammarASTWithOptions implements RuleElementAST {
+
+ public TerminalAST(TerminalAST node) {
+ super(node);
+ }
+
+ public TerminalAST(Token t) { super(t); }
+ public TerminalAST(int type) { super(type); }
+ public TerminalAST(int type, Token t) { super(type, t); }
+
+ @Override
+ public TerminalAST dupNode() { return new TerminalAST(this); }
+
+ @Override
+ public Object visit(GrammarASTVisitor v) { return v.visit(this); }
+}