It works!!!! (kinda!)
OK, here is what I needed to do:
0) I want the lexer to read from a file. I could open a fstream in
antlr2 and antlr3. Antlr4 says I can't do that. Instead, when I ended
up doing was reading the input file into a string using an
istreambuf_iterator (using a hack I found on SO), then having the lexer
read from the string. My code looks like:
ifile.open(infilename);
std::istreambuf_iterator<char> eos;
std::string istring(std::istreambuf_iterator<char>(ifile), eos);
ANTLRInputStream istream(istring);
tblLexer lexer(&istream);
Is there a more direct way? I was used to doing (in antlr2):
ifile.open(infilename)
TBLLexer lexer(ifile);
1) references to return values need to look like:
$rulename.ctx->returnvaluename
so, the pertinent rules from my grammar end up looking like:
> namedef
> : LET NAME EQ argument SEMICOLON
> { defineName($NAME.text, $argument.ctx->v); }
> ;
> argumentList
> : argument
> { table.push_back($argument.ctx->v); }
> ( COMMA argument
> { table.push_back($argument.ctx->v); }
> )*
> ;
> argument returns [ int v ]
> : constantValue
> { $v = $constantValue.ctx->v; }
> ( PLUS v2=constantValue
> { $v += $v2.ctx->v; }
> | MINUS v3=constantValue
> { $v -= $v3.ctx->v; }
> )*
> ;
> constantValue returns [ int v ]
> : NAME
> { namePtr np = lookupName($NAME.text);
> if (np != declaredNames.end())
> $v = np->second.getValue();
> else
> error(undefinedName, $NAME.text, $NAME.line);
> }
> |
> INTEGER
> { $v = $INTEGER.int; }
> ;
Strange how I need to know the "name" of the returned value and need to
use it in the rule that needs it (the ->v part of the references).
OK, antlr4 now runs over the .g4 file without error.
In general, I think this feature needs more documentation and some
examples on how to use it properly. I have some more complicated
grammars that use return values (and arguments) heavily. But, those
grammars used to generate ASTs. I guess I'm going to have to change
them to use visitors/listeners with Antlr4 and build my own ASTs.
2) Now I need to edit the generated Lexer.h, Parser.h, Lexer.cpp, and
Parser.cpp files, and change the following lines:
using namespace antlr4;
to
using namespace org::antlr::v4::runtime
Now all the code compiles without error (main, lexer, parser).
3) Linked by including the libantlr4.a file from the cloned git (after
building it).
4) Now I can run my program, and it generates the same output as my
antlr2 and antlr3 versions for the same input files! Success!
Thank for all the help Mike. I assume that 2) is something that changed
in the development stuff, and will eventually work without manual
intervention?