DFA Prediction and Coverage

Beginning with this grammar: https://stackoverflow.com/a/166268/2126252/ I would understand a simple grammar that accepts and evaluates a simple language as follows:

{ if a==c { a if a==b { b } else { c } } } 

So, if a==c , it executes a and evaluates if a==b , if it is true, it executes b otherwise c . Really simple.

The parser grammar and tree grammar are as follows:

TreeEvaluator.g (Combined Grammar for AST)

 grammar TreeEvaluator; options { output = AST; } tokens { CONDBLOCK; CODEBLOCK; DEFAULT; } compilationUnit : block EOF -> block; condition : cif elif* celse? -> ^(IF cif elif* celse?); cif : IF expr block -> ^(CONDBLOCK expr block); elif : ELIF expr block -> ^(CONDBLOCK expr block); celse : ELSE block -> ^(DEFAULT block); expr : ID EQ^ ID; block : LCUR instruction* RCUR -> ^(CODEBLOCK instruction*); instruction : ID | condition; IF : 'if'; ELIF: 'elif'; ELSE: 'else'; LCUR: '{'; RCUR: '}'; EQ : '=='; ID : ('a'..'z'|'A'..'Z')+; WS : (' '|'\t'|'\f'|'\r'|'\n')+ {skip();}; 

AstTreeEvaluatorParser.g (tree parser)

 tree grammar AstTreeEvaluatorParser; options { output = AST; tokenVocab = TreeEvaluator; ASTLabelType = CommonTree; } @members { private static final class Evaluation { boolean matched = false; boolean done = false; } private java.util.HashMap<String, Integer> vars = new java.util.HashMap<String, Integer>(); public void addVar(String name, int value){ vars.put(name, value); } } compilationUnit : block+; block : ^(CODEBLOCK instruction*); instruction : ifStat | ID; ifStat @init { Evaluation eval = new Evaluation(); } : ^(IF condition[eval]* defcond[eval]?) ; condition [Evaluation eval] : ^(CONDBLOCK exp {if ($exp.value) eval.matched = true;} evalblock[eval]) ; defcond [Evaluation eval] : ^(DEFAULT {eval.matched = true;} evalblock[eval]) //force a match ; evalblock [Evaluation eval] : {eval.matched && !eval.done}? //Only do this when a condition is matched but not finished block //call the execution code {eval.done = true;} //evaluation is complete. | ^(CODEBLOCK .*) //read the code node and continue without executing ; exp returns [boolean value] : ^(EQ lhs=ID rhs=ID) {$value = vars.get($lhs.getText()) == vars.get($rhs.getText());} ; 

The problem is that the DFA generated to predict the evalblock rule, this DFA has a SpecialStateTransition() method that refers to the eval parameter (as specified in the rule), but this parameter is not visible in the generated Java class.

I do not understand why, and if there is a way to avoid this problem.

+4
source share
1 answer

You have a semantic predicate (syntax {...}? ) That contains a reference to a value that is changed by an action (syntax {...} ). In your case, these are the fields Evaluation.matched and Evaluation.done .

You should avoid this situation altogether - never include a predicate that depends on the action. Instead, check these values โ€‹โ€‹in actions by wrapping the action code in if (eval.matched && !eval.done) { ... }

ยน There are people who write grammars who interact in this way, but I strictly avoid this because of the potential problems you see and others that are even worse.

+2
source

Source: https://habr.com/ru/post/1469252/


All Articles