One Pass Model Tree Hierarchy Creation with a C# target
In short, I'm wondering how to properly build model hierarchies from within an ANTLR grammar in one pass and what the proper way to do that is with the current C# code generation. Accessing return variables does not currently seem to work, as described in the docs.
See this example from the documentation
field
: d=decl ';' {System.out.println("type "+$d.type+", vars="+$d.vars);}
;
decl returns [String type, List vars]
: t=type ids+=ID (',' ids+=ID)* {$type = $t.text; $vars = $ids;}
;
My implementation is in C#, but the C# target documentation (circa 2008?) doesn't mention any deviations from the standard action pattern within grammars. I'm using ANTLRWorks 1.4 (not the latest 1.4.2 as of this writing) due to this. My implementation, which basically populates a 1 deep tree hierarchy with nested innerStats:
alias returns [IStatement alias]
// Alias(string identifier, List<Statement> value, StatementTy开发者_JAVA百科pe statementType, MetaData metaData)
@init { List<IStatement> innerList = new List<IStatement>(); }
: ^(ALIAS ID ( id=innerStat{if($id != null) {innerList.Add($id.myInnerStat);}} )+ ) {$alias = new Alias($ID.ToString(), innerList , StatementType.Alias, null) as IStatement; }
;
innerStat returns [IStatement myInnerStat]
: s=simpleAlias { myInnerStat = $s; }
| s=simpleBind { myInnerStat = $s; }
| s=command { myInnerStat = $s; }
| increment { myInnerStat = null; }
| s=exec { myInnerStat = $s; }
;
simpleAlias returns [IStatement myAlias]
// Alias(string identifier, List<Statement> value, StatementType statementType, MetaData metaData)
@init{ myAlias= null; string id1 = null; string id2 = null; }
@after{ myAlias = (new Alias(id1, id2, StatementType.Alias, null)) as IStatement; }
: ^(ALIAS ID) { id1 = $ID.ToString(); }
| ^(ALIAS i1=ID i2=ID) { id1 = $i1.ToString(); id2 = $i2.ToString(); }
;
This returns the following errors:
error(117): D:/Files/.../SourceEval.g:39:29: missing attribute access on rule scope: id
error(117): D:/Files/.../SourceEval.g:43:18: missing attribute access on rule scope: s
error(117): D:/Files/.../SourceEval.g:44:17: missing attribute access on rule scope: s
error(117): D:/Files/.../SourceEval.g:45:14: missing attribute access on rule scope: s
error(117): D:/Files/.../SourceEval.g:47:11: missing attribute access on rule scope: s
Currently, the only way I see to around this problem is to create a method within my C# model and then call Model.Aliases.Last().AddChild(IStatement)
from within innerStat, which breaks encapsulation. Thanks for any help.
edit: The corrected code can be found here: https://github.com/keithharvey/Script-Parser/blob/master/Installer/Model/DAL/SourceExpr.g
Notice how the examples always refer to an attribute of a rule:
$d.type
$d.vars
$t.text
except the $ids
, but that one isn't a rule because the +=
makes it a List
.
Your code has 5 illegal usages of rule attributes (or the absence of them):
1
$id != null
is invalid because you didn't use an attribute at all, try: $id.myInnerStat != null
instead.
2
s=exec { myInnerStat = $s; }
is wrong because you didn't use an attribute at all, you need to access an attribute of exec
(you didn't post that rule, so I don't know what).
3, 4, 5
$ID.ToString()
, $i1.ToString()
and $i2.ToString()
are wrong, ToString()
isn't an valid attribute of ID
. Try $ID.text
, etc. instead.
精彩评论