Listener-Parser in ANTLR4 - parsing

ANTLR4 rule :
listExpr locals [Object in, Object out] : ( expr ',')* expr ;
Parser :
public static class ListExprContext extends ParserRuleContext {
public Object in;
public Object out;
public List<ExprContext> expr() {
return getRuleContexts(ExprContext.class);
}
....
}
Listener :
override def exitListExpr(ctx : BKOOLParser.ListExprContext) : Unit =
{
val listExpr = ctx.expr
val length = listExpr.length
ctx.out = length
}
I want to have the numbers of expr I have in ListExpr,but I have the error :
the result type of an implicit must be more specific than AnyRef
at line :
ctx.out = length
How to fix it ? Your help will be appreciated .

Related

Can ANTLR's Visitor system automatically visit a rule context when a file is parsed?

I been using ANTLR for a month now and I'm still no expert. I wanted to know if ANTLR's BaseVisitor class that is generated, automatically visits a specific rule context once the visitRuleContext() is implemented and the file to be parsed is done so.
Yes, if you look into the generated visitor class, you'll see that all methods return visitChildren(ctx). So when you only override one visit...(...) method in your own visitor, your single method would be called.
A quick test shows this:
grammar T;
parse
: something+ EOF
;
something
: ANY+
| number
;
number
: DIGITS
;
DIGITS
: [0-9]+
;
ANY
: .
;
And a test class:
public class Main {
public static void main(String[] args) throws Exception {
TLexer lexer = new TLexer(CharStreams.fromString("mu 123"));
TParser parser = new TParser(new CommonTokenStream(lexer));
ParseTree root = parser.parse();
new TestVisitor().visit(root);
}
}
class TestVisitor extends TBaseVisitor<Object> {
#Override
public Object visitSomething(TParser.SomethingContext ctx) {
System.out.println("visitSomething: " + ctx.getText());
return super.visitChildren(ctx);
}
}
will print:
visitSomething: mu
visitSomething: 123

C# ANTLR4 DefaultErrorStrategy or custom error listener does not catch unrecognized characters

It's quite strange, but DefaultErrorStrategy does not do anything for catching unrecognized characters from a stream. I tried a custom error strategy, a custom error listener and BailErrorStrategy - no luck here.
My grammar
grammar Polynomial;
parse : canonical EOF
;
canonical : polynomial+ #canonicalPolynom
| polynomial+ EQUAL polynomial+ #equality
;
polynomial : SIGN? '(' (polynomial)* ')' #parens
| monomial #monom
;
monomial : SIGN? coefficient? VAR ('^' INT)? #addend
| SIGN? coefficient #number
;
coefficient : INT | DEC;
INT : ('0'..'9')+;
DEC : INT '.' INT;
VAR : [a-z]+;
SIGN : '+' | '-';
EQUAL : '=';
WHITESPACE : (' '|'\t')+ -> skip;
and I'm giving an input 23*44=12 or #1234
I'm expecting that my parser throws mismatched token or any kind of exception for a character * or # that is not defined in my grammar.
Instead, my parser just skips * or # and traverse a tree like there are do not exist.
My handler function where I'm calling lexer, parser and that's kind of stuff.
private static (IParseTree tree, string parseErrorMessage) TryParseExpression(string expression)
{
ICharStream stream = CharStreams.fromstring(expression);
ITokenSource lexer = new PolynomialLexer(stream);
ITokenStream tokens = new CommonTokenStream(lexer);
PolynomialParser parser = new PolynomialParser(tokens);
//parser.ErrorHandler = new PolynomialErrorStrategy(); -> I tried custom error strategy
//parser.RemoveErrorListeners();
//parser.AddErrorListener(new PolynomialErrorListener()); -> I tried custom error listener
parser.BuildParseTree = true;
try
{
var tree = parser.canonical();
return (tree, string.Empty);
}
catch (RecognitionException re)
{
return (null, re.Message);
}
catch (ParseCanceledException pce)
{
return (null, pce.Message);
}
}
I tried to add a custom error listener.
public class PolynomialErrorListener : BaseErrorListener
{
private const string Eof = "EOF";
public override void SyntaxError(TextWriter output, IRecognizer recognizer, IToken offendingSymbol, int line, int charPositionInLine, string msg,
RecognitionException e)
{
if (msg.Contains(Eof))
{
throw new ParseCanceledException($"{GetSyntaxErrorHeader(charPositionInLine)}. Missing an expression after '=' sign");
}
if (e is NoViableAltException || e is InputMismatchException)
{
throw new ParseCanceledException($"{GetSyntaxErrorHeader(charPositionInLine)}. Probably, not closed operator");
}
throw new ParseCanceledException($"{GetSyntaxErrorHeader(charPositionInLine)}. {msg}");
}
private static string GetSyntaxErrorHeader(int errorPosition)
{
return $"Expression is invalid. Input is not valid at {--errorPosition} position";
}
}
After that, I tried to implement a custom error strategy.
public class PolynomialErrorStrategy : DefaultErrorStrategy
{
public override void ReportError(Parser recognizer, RecognitionException e)
{
throw e;
}
public override void Recover(Parser recognizer, RecognitionException e)
{
for (ParserRuleContext context = recognizer.Context; context != null; context = (ParserRuleContext) context.Parent) {
context.exception = e;
}
throw new ParseCanceledException(e);
}
public override IToken RecoverInline(Parser recognizer)
{
InputMismatchException e = new InputMismatchException(recognizer);
for (ParserRuleContext context = recognizer.Context; context != null; context = (ParserRuleContext) context.Parent) {
context.exception = e;
}
throw new ParseCanceledException(e);
}
protected override void ReportInputMismatch(Parser recognizer, InputMismatchException e)
{
string msg = "mismatched input " + GetTokenErrorDisplay(e.OffendingToken);
// msg += " expecting one of " + e.GetExpectedTokens().ToString(recognizer.());
RecognitionException ex = new RecognitionException(msg, recognizer, recognizer.InputStream, recognizer.Context);
throw ex;
}
protected override void ReportMissingToken(Parser recognizer)
{
BeginErrorCondition(recognizer);
IToken token = recognizer.CurrentToken;
IntervalSet expecting = GetExpectedTokens(recognizer);
string msg = "missing " + expecting.ToString() + " at " + GetTokenErrorDisplay(token);
throw new RecognitionException(msg, recognizer, recognizer.InputStream, recognizer.Context);
}
}
Is there any flag that I forgot to specify in a parser or I have incorrect grammar?
Funny thing that I'm using ANTLR plugin in my IDE and when I'm testing my grammar in here this plugin correctly responds with line 1:2 token recognition error at: '*'
Full source code: https://github.com/EvgeniyZ/PolynomialCanonicForm
I'm using ANTLR 4.8-complete.jar
Edit
I tried to add to a grammar rule
parse : canonical EOF
;
Still no luck here
What happens if you do this:
parse
: canonical EOF
;
and also invoke this rule:
var tree = parser.parse();
By adding the EOF token (end of input), you are forcing the parser to consume all tokens, which should result in an error when the parser cannot handle them properly.
Funny thing that I'm using ANTLR plugin in my IDE and when I'm testing my grammar in here this plugin correctly responds with line 1:2 token recognition error at: '*'
That is what the lexer emits on the std.err stream. The lexer just reports this warning and goes its merry way. So the lexer just ignores these chars and therefor never end up in the parser. If you add the following line at the end of your lexer:
// Fallback rule: matches any single character if not matched by another lexer rule
UNKNOWN : . ;
then the * and # chars will be sent to the parser as UNKNOWN tokens and should then cause recognition errors.

ANTLR's parser enters into "wrong" rule

I'm trying to create an interpreter for a simple programming language using ANTLR. So far it consists of print and numeric expressions.
I created a 'simpleExpr' parser rule to handle negative numbers. I tried other ways, too, but that's the only one which seems to work right for me. However, for some reason my visitor enters to this rule, even if I would expect it to visit my 'number' rule. I really think, that it's not the visitor's fault, because even the tree drawn by ANTLR shows this behavior. It's weird, but it would be OK, but my problem is, that when I try to print out the result of a simple addition, e.g. print(1+2); then it doesn't do that, but enters into 'number' rule instead of 'Plus' rule.
My grammar:
grammar BatshG;
/*
* Parser Rules
*/
compileUnit: (expression | ( println ';') | ( print ';' ))+;
expression:
left=expression '/' right=simpleExpr #Divi
| left=expression '*' right=simpleExpr #Mult
| left=expression '-' right=simpleExpr #Minus
| left=expression '+' right=simpleExpr #Plus
| number=simpleExpr #Number
;
println: 'println' '(' argument=expression ')';
print: 'print' '(' argument=expression ')';
simpleExpr
: (MINUS)?
(FLOAT | INTEGER)
;
MINUS: '-';
INTEGER: [0-9] [0-9]*;
DIGIT : [0-9] ;
FRAC : '.' DIGIT+ ;
EXP : [eE] [-+]? DIGIT+ ;
FLOAT : DIGIT* FRAC EXP? ;
WS: [ \n\t\r]+ -> channel(HIDDEN);
If it helps, here is my visualized tree generated by ANTLR for
print(1+2);
Update:
The visitor class, if it counts:
public class BatshGVisitor : BatshGBaseVisitor<ResultValue>
{
public ResultValue Result { get; set; }
public StringBuilder OutputForPrint { get; set; }
public override ResultValue VisitCompileUnit([NotNull] BatshGParser.CompileUnitContext context)
{
OutputForPrint = new StringBuilder("");
var resultvalue = VisitChildren(context);
Result = new ResultValue() { ExpType = "string", ExpValue = resultvalue.ExpValue };
return Result;
}
public override ResultValue VisitPlus([NotNull] BatshGParser.PlusContext context)
{
var leftExp = VisitChildren(context.left);
var rigthExp = VisitChildren(context.right);
return new ResultValue()
{
ExpType = "number",
ExpValue = (double)leftExp.ExpValue + (double)rigthExp.ExpValue
};
}
//public override ResultValue VisitNumber([NotNull] BatshGParser.NumberContext context)
//{
// return new ResultValue()
// {
// ExpType = "number",
// ExpValue = Double.Parse(context.GetChild(0).GetText()
// + context.GetChild(1).GetText()
// + context.GetChild(2).GetText()
// , CultureInfo.InvariantCulture)
// };
//}
public override ResultValue VisitPrint([NotNull] BatshGParser.PrintContext context)
{
var viCh = VisitChildren(context.argument);
var viChVa = viCh.ExpValue;
string printInner = viChVa.ToString();
var toPrint = new ResultValue()
{
ExpType = viCh.ExpType,
ExpValue = printInner
};
OutputForPrint.Append(toPrint.ExpValue);
return toPrint;
}
public override ResultValue VisitSimpleExpr([NotNull] BatshGParser.SimpleExprContext context)
{
string numberToConvert = "";
if (context.ChildCount == 1)
{
numberToConvert = context.GetChild(0).GetText();
}
else if (context.GetChild(0).ToString() == "-")
{
if (context.ChildCount == 2)
{
numberToConvert = "-" + context.GetChild(1);
}
if (context.ChildCount == 4)
{
numberToConvert = context.GetChild(0).ToString() + context.GetChild(1).ToString() +
context.GetChild(2).ToString() + context.GetChild(3).ToString();
}
}
return new ResultValue()
{
ExpType = "number",
ExpValue = Double.Parse(numberToConvert, CultureInfo.InvariantCulture)
};
}
protected override ResultValue AggregateResult(ResultValue aggregate, ResultValue nextResult)
{
if (aggregate == null)
return new ResultValue()
{
ExpType = nextResult.ExpType,
ExpValue = nextResult.ExpValue
};
if (nextResult == null)
{
return aggregate;
}
return null;
}
}
What's the problem with my grammar?
Thank you!
Inside the visit method for print statements, you have this:
var viCh = VisitChildren(context.argument);
So let's say your input was print(1+2);. Then context.argument would be the PlusContext for 1+2 and the children of context.argument would be a NumberContext for 1, a Token object for + and a SimpleExpression object for 2. So by calling VisitChildren, you're going to visit those children, which is why it never runs VisitPlus and goes directly to the numbers.
Generally, you rarely want to visit the children of some other node. You usually want to visit your own children, not skip the children and directly visit the grand children. So what you should do instead is to call Visit(context.argument);.

Xtext: Use EClass in XExpression

I am writing on a Xtext grammar that uses XExpressions and also operates on Eclasses. Now I want to also be able to access Eclasses from the XExpression, for example I write an expression like this:
Eclass1.attribute1 = Eclass2.attribute1
I would like to know, how I can use the Eclass from within the XExpression?
Grammar
grammar org.xtext.example.mydsl.Mydsl with
org.eclipse.xtext.xbase.Xbase
import "http://www.eclipse.org/emf/2002/Ecore" as ecore
generate mydsl "http://www.xtext.org/example/mydsl/Mydsl"
Model:
(operations += Operation)*;
terminal ATTR : ID ('.' ID)+;
Operation:
'operation' left=[ecore::EClass|ATTR] 'and' right=
[ecore::EClass|ATTR] 'defined' 'as' condition=XExpression
;
Inferrer/ Infer method
def dispatch void infer(Model element, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) {
acceptor.accept(element.toClass("example.mydsl")) [
for (operation : element.operations) {
left = operation.left
right = operation.right
if (left.eIsProxy()) {
left = EcoreUtil.resolve(left, operation) as EClass
}
if (right.eIsProxy()) {
right = EcoreUtil.resolve(right, operation) as EClass
}
//field for right class left out, but works the same
members += left.toField(left.name,typeRef(left.EPackage.name+"."+left.name))
members += operation.toMethod("conditionExpr",
typeRef(Void.TYPE)) [
body = operation.condition
]
}
]
}
RuntimeModule
class MyDslRuntimeModule extends AbstractMyDslRuntimeModule {
def Class<? extends ImplicitlyImportedFeatures> bindImplicitlyImportedTypes() {
return MyImportFeature
}
}
MyImportFeature
class MyImportFeature extends ImplicitlyImportedFeatures{
override protected getStaticImportClasses() {
(super.getStaticImportClasses() + #[PackageFromWorkSpace]).toList
}
}
I Am not sure if i get your question.
Ususally EMF generates constants for EAttributes so if you want to access the attributes themselfs
so you could either do
MyDslPackage.Literals.GREETING__NAME
or
MyDslPackage.eINSTANCE.getGreeting_Name()
can you give some more hints on what you actually want to do
update: here is a snippet on how to get a java class from a reference to an eclass
Thingy:{
val EClass eclazz = f.clazz
val uri = EcorePlugin.getEPackageNsURIToGenModelLocationMap(true).get(eclazz.EPackage.nsURI)
val rs = new ResourceSetImpl
val r = rs.getResource(uri, true)
r.load(null)
val p = r.contents.head
if (p instanceof GenModel) {
val genClass = p.findGenClassifier(eclazz)
if (genClass instanceof GenClass) {
println(genClass.qualifiedInterfaceName)
members+=f.toField(eclazz.name, genClass.qualifiedInterfaceName.typeRef)
}
}
}

javacc java.lang.NullPointerException

im trying to make a miniJava parser but im having trouble figuring out a way to parse method declarations that have no formal parameters.
e.g public int getNumber()
The code that i have right now works for parameters of one or more, but im not sure how to return an empty formal object as clearly the problem lies with the line returning null.
Is there a way to skip the return statement altogether and return nothing?
public Formal nt_FormalList() :
{
Type t;
Token s;
LinkedList<Formal> fl = new LinkedList<Formal>();
Formal f;
}
{
t = nt_Type() s = <IDENTIFIER> (f = nt_FormalRest() {fl.add(f);})*
{ return new Formal(t, s.image); }
| {}
{ return null; }
}
.....
public class Formal {
public final Type t;
public final String i;
public Formal(Type at, String ai) {
t = at;
i = ai;
}
I'd suggest that you return list of Formals from nt_FormalList.
public List<Formal> nt_FormalList() :
{
LinkedList<Formal> fl = new LinkedList<Formal>();
Formal f;
}
{
[ f = nt_Formal() {fl.add(f);}
(<COMMA> f = nt_Formal() {fl.add(f);})*
]
{ return fl; }
}

Resources