[git-p4: depot-paths = "//depot/code/antlr4/main/": change = 6845]
This commit is contained in:
parrt 2010-05-07 13:12:28 -08:00
parent 07625981fb
commit 5baff5d37e
12 changed files with 235 additions and 38 deletions

View File

@ -0,0 +1,29 @@
// args must be <object-model-object>, <fields-resulting-in-STs>
parserFile(f, parser) ::= <<
// $ANTLR ANTLRVersion> <f.fileName> generatedTimestamp>
import org.antlr.runtime.*;
<parser>
>>
parser(p,funcs,dfaDefs) ::= <<
public class <p.name> {
<funcs>
<dfaDefs>
}
>>
DFA(dfa) ::= <<
// define <dfa.name>
>>
parserFunction(f,code) ::= <<
<f.modifiers:{f | <f> }>void <f.name>(<f.args>) {
<code>
}
>>
codeFileExtension() ::= ".java"
true() ::= "true"
false() ::= "false"

View File

@ -76,17 +76,20 @@ FILENAME_EXTENSION_ERROR(arg) ::=
// code gen errors
MISSING_CODE_GEN_TEMPLATES(arg) ::=
"cannot find code generation templates <arg>.stg"
"cannot find code generation templates for language <arg>"
MISSING_CYCLIC_DFA_CODE_GEN_TEMPLATES() ::=
"cannot find code generation cyclic DFA templates for language <arg>"
CODE_GEN_TEMPLATES_INCOMPLETE(arg) ::=
"at least one code generation template missing for language <arg>"
"missing code generation template <arg>"
CANNOT_CREATE_TARGET_GENERATOR(arg,exception,stackTrace) ::=
"cannot create target <arg> code generator: <exception>"
CANNOT_COMPUTE_SAMPLE_INPUT_SEQ() ::=
"cannot generate a sample input sequence from lookahead DFA"
CODE_TEMPLATE_ARG_ISSUE(arg,arg2) ::=
"code generation template <arg> has missing, misnamed, or incomplete arg list: <arg2>"
NO_MODEL_TO_TEMPLATE_MAPPING(arg) ::=
"no mapping to template name for output model class <arg>"
CANNOT_COMPUTE_SAMPLE_INPUT_SEQ() ::=
"cannot generate a sample input sequence from lookahead DFA"
// grammar interpretation errors
/*

View File

@ -51,7 +51,14 @@ public abstract class CodeGenerator {
}
public void loadTemplates(String language) {
templates = new STGroupFile(TEMPLATE_ROOT+"/"+language+"/"+language+".stg");
try {
templates = new STGroupFile(TEMPLATE_ROOT+"/"+language+"/"+language+".stg");
}
catch (IllegalArgumentException iae) {
g.tool.errMgr.toolError(ErrorType.CANNOT_CREATE_TARGET_GENERATOR,
language);
}
// if ( EMIT_TEMPLATE_DELIMITERS ) {
// templates.emitDebugStartStopStrings(true);
// templates.doNotEmitDebugStringsForTemplate("codeFileExtension");
@ -59,6 +66,7 @@ public abstract class CodeGenerator {
// }
}
/** The parser, tree parser, etc... variants know to build the model */
public abstract OutputModelObject buildOutputModel();
public void write() {
@ -70,11 +78,11 @@ public abstract class CodeGenerator {
// WRITE FILES
try {
target.genRecognizerFile(g.tool,this,g,outputFileST);
target.genRecognizerFile(this,g,outputFileST);
if ( templates.isDefined("headerFile") ) {
ST extST = templates.getInstanceOf("headerFileExtension");
ST headerFileST = null;
target.genRecognizerHeaderFile(g.tool,this,g,headerFileST,extST.render());
target.genRecognizerHeaderFile(this,g,headerFileST,extST.render());
}
// // write out the vocab interchange file; used by antlr,
// // does not change per target

View File

@ -6,11 +6,10 @@ import org.antlr.v4.tool.ErrorType;
import org.stringtemplate.v4.ST;
import org.stringtemplate.v4.STGroup;
import org.stringtemplate.v4.compiler.FormalArgument;
import org.stringtemplate.v4.misc.BlankST;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import java.util.*;
/** Convert output model tree to template hierarchy */
public class OutputModelWalker {
@ -30,29 +29,52 @@ public class OutputModelWalker {
public ST walk(OutputModelObject omo) {
// CREATE TEMPLATE FOR THIS OUTPUT OBJECT
String templateName = modelToTemplateMap.get(omo.getClass());
if ( templateName == null ) {
tool.errMgr.toolError(ErrorType.NO_MODEL_TO_TEMPLATE_MAPPING, omo.getClass().getSimpleName());
return new BlankST();
}
ST st = templates.getInstanceOf(templateName);
if ( st.impl.formalArguments== FormalArgument.UNKNOWN ) {
if ( st == null ) {
tool.errMgr.toolError(ErrorType.CODE_GEN_TEMPLATES_INCOMPLETE, templateName);
return new BlankST();
}
if ( st.impl.formalArguments == FormalArgument.UNKNOWN ) {
tool.errMgr.toolError(ErrorType.CODE_TEMPLATE_ARG_ISSUE, templateName, "<none>");
return st;
}
// todo: chk arg-field mismtch
Set<String> argNames = st.impl.formalArguments.keySet();
String arg = argNames.iterator().next(); // should be just one
// PASS IN OUTPUT OBJECT TO TEMPLATE
st.add(arg, omo); // set template attribute of correct name
List<String> kids = omo.getChildren();
for (String fieldName : omo.getChildren()) {
if ( argNames.contains(fieldName) ) continue; // they won't use so don't compute
LinkedHashMap<String,FormalArgument> formalArgs = st.impl.formalArguments;
Set<String> argNames = formalArgs.keySet();
Iterator<String> it = argNames.iterator();
// PASS IN OUTPUT MODEL OBJECT TO TEMPLATE
String modelArgName = it.next(); // ordered so this is first arg
st.add(modelArgName, omo);
// ENSURE TEMPLATE ARGS AND CHILD FIELDS MATCH UP
while ( it.hasNext() ) {
String argName = it.next();
if ( !kids.contains(argName) ) {
tool.errMgr.toolError(ErrorType.CODE_TEMPLATE_ARG_ISSUE, templateName, argName);
return st;
}
}
// COMPUTE STs FOR EACH NESTED MODEL OBJECT NAMED AS ARG BY TEMPLATE
if ( kids!=null ) for (String fieldName : kids) {
if ( !argNames.contains(fieldName) ) continue; // they won't use so don't compute
//System.out.println("computing ST for field "+fieldName+" of "+omo.getClass());
try {
Field fi = omo.getClass().getField(fieldName);
Object o = fi.get(omo);
if ( o instanceof OutputModelObject ) {
if ( o instanceof OutputModelObject ) { // SINGLE MODEL OBJECT?
OutputModelObject nestedOmo = (OutputModelObject)o;
ST nestedST = walk(nestedOmo);
st.add(fieldName, nestedST);
}
else if ( o instanceof Collection) {
else if ( o instanceof Collection ) { // LIST OF MODEL OBJECTS?
Collection<? extends OutputModelObject> nestedOmos = (Collection)o;
for (OutputModelObject nestedOmo : nestedOmos) {
ST nestedST = walk(nestedOmo);
@ -64,7 +86,7 @@ public class OutputModelWalker {
}
}
catch (NoSuchFieldException nsfe) {
tool.errMgr.toolError(ErrorType.CODE_TEMPLATE_ARG_ISSUE, templateName, fieldName);
tool.errMgr.toolError(ErrorType.CODE_TEMPLATE_ARG_ISSUE, templateName, nsfe.getMessage());
}
catch (IllegalAccessException iae) {
tool.errMgr.toolError(ErrorType.CODE_TEMPLATE_ARG_ISSUE, templateName, fieldName);

View File

@ -1,9 +1,6 @@
package org.antlr.v4.codegen;
import org.antlr.v4.codegen.src.OutputModelObject;
import org.antlr.v4.codegen.src.Parser;
import org.antlr.v4.codegen.src.ParserFile;
import org.antlr.v4.codegen.src.RuleFunction;
import org.antlr.v4.codegen.src.*;
import org.antlr.v4.tool.Grammar;
import java.util.HashMap;
@ -16,6 +13,7 @@ public class ParserGenerator extends CodeGenerator {
put(ParserFile.class, "parserFile");
put(Parser.class, "parser");
put(RuleFunction.class, "parserFunction");
put(DFADef.class, "DFA");
}};
public ParserGenerator(Grammar g) {
@ -24,8 +22,6 @@ public class ParserGenerator extends CodeGenerator {
public OutputModelObject buildOutputModel() {
Parser p = new Parser(g);
ParserFile f = new ParserFile(p, getRecognizerFileName());
return f;
return new ParserFile(p, getRecognizerFileName());
}
}

View File

@ -0,0 +1,114 @@
tree grammar SourceGenTriggers;
options {
language = Java;
tokenVocab = ANTLRParser;
ASTLabelType = GrammarAST;
// superClass = NFABytecodeGenerator;
}
@header {
package org.antlr.v4.codegen;
import org.antlr.v4.codegen.nfa.*;
import org.antlr.v4.tool.GrammarAST;
import org.antlr.v4.tool.GrammarASTWithOptions;
import org.antlr.v4.tool.LexerGrammar;
import java.util.Collections;
import java.util.Map;
import java.util.HashMap;
}
block
: ^( BLOCK (^(OPTIONS .+))?
( alternative
)+
)
;
alternative
: ^(ALT_REWRITE a=alternative .)
| ^(ALT EPSILON)
| ^(ALT (e=element )+)
;
element
: labeledElement
| atom
| ebnf
| ACTION
| SEMPRED
| GATED_SEMPRED
| treeSpec
;
labeledElement
: ^(ASSIGN ID atom )
| ^(ASSIGN ID block)
| ^(PLUS_ASSIGN ID atom)
| ^(PLUS_ASSIGN ID block)
;
treeSpec
: ^(TREE_BEGIN (e=element )+)
;
ebnf
@init {
GrammarASTWithOptions blk = (GrammarASTWithOptions)$start.getChild(0);
String greedyOption = blk.getOption("greedy");
}
: ^(astBlockSuffix block)
| ^(OPTIONAL block)
| ^(CLOSURE block)
| ^(POSITIVE_CLOSURE block)
| block
;
astBlockSuffix
: ROOT
| IMPLIES
| BANG
;
atom
: ^(ROOT range)
| ^(BANG range)
| ^(ROOT notSet)
| ^(BANG notSet)
| notSet
| range
| ^(DOT ID terminal)
| ^(DOT ID ruleref)
| ^(WILDCARD .)
| WILDCARD
| terminal
| ruleref
;
notSet
: ^(NOT terminal)
| ^(NOT block)
;
ruleref
: ^(ROOT ^(RULE_REF ARG_ACTION?))
| ^(BANG ^(RULE_REF ARG_ACTION?))
| ^(RULE_REF ARG_ACTION?)
;
range
: ^(RANGE a=STRING_LITERAL b=STRING_LITERAL)
;
terminal
: ^(STRING_LITERAL .)
| STRING_LITERAL
| ^(TOKEN_REF ARG_ACTION .)
| ^(TOKEN_REF .)
| TOKEN_REF
| ^(ROOT terminal)
| ^(BANG terminal)
;

View File

@ -1,6 +1,5 @@
package org.antlr.v4.codegen;
import org.antlr.v4.Tool;
import org.antlr.v4.automata.Label;
import org.antlr.v4.tool.Grammar;
import org.stringtemplate.v4.ST;
@ -36,9 +35,8 @@ public class Target {
ANTLRLiteralCharValueEscape['\''] = "\\'";
}
protected void genRecognizerFile(Tool tool,
CodeGenerator generator,
Grammar grammar,
protected void genRecognizerFile(CodeGenerator generator,
Grammar g,
ST outputFileST)
throws IOException
{
@ -46,9 +44,8 @@ public class Target {
generator.write(outputFileST, fileName);
}
protected void genRecognizerHeaderFile(Tool tool,
CodeGenerator generator,
Grammar grammar,
protected void genRecognizerHeaderFile(CodeGenerator generator,
Grammar g,
ST headerFileST,
String extName) // e.g., ".h"
throws IOException

View File

@ -6,5 +6,9 @@ import org.antlr.v4.automata.DFA;
public class DFADef extends OutputModelObject {
public String name;
public DFA dfa;
public DFADef(String name, DFA dfa) {
this.dfa = dfa;
this.name = name;
}
}

View File

@ -4,7 +4,7 @@ import java.util.List;
/** */
public abstract class OutputModelObject {
//public abstract ST getSt();
//public ST st;
/** If the output model object encloses some other model objects,
* we need to be able to walk them. Rather than make each class
@ -13,6 +13,7 @@ public abstract class OutputModelObject {
* as a homogeneous tree structure. Returns a list of field names
* of type OutputModelObject that should be walked to complete model.
*/
// TODO: make list of Fields to avoid repeated look up
public List<String> getChildren() {
return null;
}

View File

@ -1,5 +1,6 @@
package org.antlr.v4.codegen.src;
import org.antlr.v4.automata.DFA;
import org.antlr.v4.misc.IntSet;
import org.antlr.v4.tool.Grammar;
import org.antlr.v4.tool.Rule;
@ -11,12 +12,17 @@ import java.util.List;
public class Parser extends OutputModelObject {
public String name;
public List<RuleFunction> funcs = new ArrayList<RuleFunction>();
public List<DFADef> dfaDefs;
public List<DFADef> dfaDefs = new ArrayList<DFADef>();
public List<IntSet> bitsetDefs;
public Parser(Grammar g) {
name = g.getRecognizerName();
for (Rule r : g.rules.values()) funcs.add( new RuleFunction(r) );
// build DFA, bitset defs
for (DFA dfa : g.decisionDFAs.values()) {
dfaDefs.add( new DFADef("DFA"+dfa.decision, dfa) );
}
}
@Override

View File

@ -1,6 +1,10 @@
package org.antlr.v4.codegen.src;
import org.antlr.runtime.tree.CommonTreeNodeStream;
import org.antlr.v4.codegen.SourceGenTriggers;
import org.antlr.v4.misc.Utils;
import org.antlr.v4.parse.ANTLRParser;
import org.antlr.v4.parse.GrammarASTAdaptor;
import org.antlr.v4.tool.Attribute;
import org.antlr.v4.tool.GrammarAST;
import org.antlr.v4.tool.Rule;
@ -40,6 +44,17 @@ public class RuleFunction extends OutputModelObject {
tokenLabels = r.getTokenRefs();
exceptions = Utils.nodesToStrings(r.exceptionActions);
if ( r.finallyAction!=null ) finallyAction = r.finallyAction.getText();
GrammarASTAdaptor adaptor = new GrammarASTAdaptor(r.ast.token.getInputStream());
GrammarAST blk = (GrammarAST)r.ast.getFirstChildWithType(ANTLRParser.BLOCK);
CommonTreeNodeStream nodes = new CommonTreeNodeStream(adaptor,blk);
SourceGenTriggers gen = new SourceGenTriggers(nodes);
try {
gen.block(); // GEN Instr OBJECTS
}
catch (Exception e){
e.printStackTrace(System.err);
}
}
@Override

View File

@ -62,6 +62,8 @@ public enum ErrorType {
MISSING_CODE_GEN_TEMPLATES(ErrorSeverity.ERROR, false, true),
CANNOT_CREATE_TARGET_GENERATOR(ErrorSeverity.ERROR, false, true),
CODE_TEMPLATE_ARG_ISSUE(ErrorSeverity.ERROR, false, true),
CODE_GEN_TEMPLATES_INCOMPLETE(ErrorSeverity.ERROR, false, true),
NO_MODEL_TO_TEMPLATE_MAPPING(ErrorSeverity.ERROR, false, true),
// Grammar errors
SYNTAX_ERROR(ErrorSeverity.ERROR, true, true),