i am working on a grammar to parse apache velocity on my own and i ran into the issue that i am not able to detect normal text neither the markup.
I am getting this message during the first line of the source.
line 1:0 extraneous input '// ${Name}.java' expecting {BREAK, FOREACH, IF, INCLUDE, PARSE, SET, STOP, '#[[', RAW_TEXT, '$'}
The input '// ${Name}.Java' should be tokenized to RAW_TEXT '$' '{' IDENTIFIER '}' RAW_TEXT. The parser rules should be rawText reference rawText. These parser rules are statements.
This is my source file. It is a java template in this case but the source file could or might be also a html template like mentioned in the user guide of apache velocity.
// ${Name}.java
#foreach ( $vertice in $Vertices )
#if ( $vertice.Type == "Class" )
public class $vertice.Name {
#foreach ( $edge in $Edges )
#if ( $edge.from == $vertice.Name)
// From $edge.from to $edge.to
private $edge.to $edge.to.toLowerCase();
public $edge.to get{$edge.to}() {
return this.${edge.to.toLowerCase()};
}
public void set${edge.to}(${edge.to} new${edge.to}) {
$edge.to old${edge.to} = this.${edge.to.toLowerCase()};
if (old${edge.to} != new${edge.to}) {
if (old${edge.to} != null) {
this.${edge.to.toLowerCase()} = null;
old${edge.to}.set${edge.from}(null);
}
this.${edge.to.toLowerCase()} = new${edge.to};
if (new${edge.to} != null) {
new${edge.to}.set${edge.from}(this);
}
}
}
public $edge.from with${edge.to}(${edge.to} new${edge.to}) {
this.set${edge.to}(new${edge.to});
return this;
}
#end
#end
}
#end
#end
This is my grammar.
grammar Velocity;
/* -- Parser Rules --- */
/*
* Start Rule
*/
template
: statementSet EOF?
;
/*
* Statements
*/
statementSet
: statement+
;
statement
: rawText # RawTextStatement
| unparsed # UnparsedStatement
| reference # ReferenceStatement
| setDirective # SetStatement
| ifDirective # IfStatement
| foreachDirective # ForeachStatement
| includeDirective # IncludeStatement
| parseDirective # ParseStatement
| breakDirective # BreakStatement
| stopDirective # StopStatement
;
rawText
: RAW_TEXT
;
unparsed
: UNPARSED UnparsedText=(TEXT | NL)* UNPARSED_END
;
setDirective
: SET '(' assignment ')'
;
ifDirective
: ifPart (elseifPart)* (elsePart)? END
;
foreachDirective
: FOREACH '(' variableReference 'in' enumerable ')' statementSet END
;
includeDirective
: INCLUDE '(' stringValue (',' stringValue)* ')'
;
parseDirective
: PARSE '(' stringValue ')'
;
breakDirective
: BREAK
;
stopDirective
: STOP
;
/*
* Expressions
*/
assignment
: assignableReference '=' expression
;
expression
: reference # ReferenceExpression
| string # StringLiteralExpression
| NUMBER # NumberLiteralExpression
| array # ArrayExpression
| map # MapExpression
| range # RangeExpression
| arithmeticOperation # ArithmeticOperationExpression
| booleanOperation # BooleanOperationExpression
;
enumerable
: array
| map
| range
| reference
;
stringValue
: string # StringValue_String
| reference # StringValue_Reference
;
/*
* References
*/
reference
: DOLLAR Quiet='!'? (referenceType | '{' referenceType '}')
;
assignableReference
: DOLLAR Quiet='!'? (assignableReferenceType | '{' assignableReferenceType '}')
;
referenceType
: assignableReferenceType # ReferenceType_AssignableReferenceType
| methodReference # ReferenceType_MethodReference
;
assignableReferenceType
: variableReference # AssignableReferenceType_VariableReference
| propertyReference # AssignableReferenceType_PropertyReference
;
variableReference
: IDENTIFIER indexNotation?
;
propertyReference
: IDENTIFIER ('.' IDENTIFIER)+ indexNotation?
;
methodReference
: IDENTIFIER ('.' IDENTIFIER)* '.' IDENTIFIER '(' (expression (',' expression)*)? ')' indexNotation?
;
indexNotation
: '[' NUMBER ']' # IndexNotation_Number
| '[' reference ']' # IndexNotation_Reference
| '[' string ']' # IndexNotation_String
;
/*
* Parsed Types
*/
string
: '"' stringText* '"' # DoubleQuotedString
| '\'' TEXT? '\'' # SingleQuotedString
;
stringText
: TEXT # StringText_Text
| reference # StringText_Reference
;
/*
* Container Types
*/
array
: '[' (expression (',' expression)*)? ']'
;
map
: '{' (expression ':' expression (',' expression ':' expression))? '}'
;
range
: '[' n=NUMBER '..' m=NUMBER ']'
;
/*
* Arithmetic Operators
*/
arithmeticOperation
: sum
;
sum
: term (followingTerm)*
;
followingTerm
: Operator=('+' | '-') term
;
term
: factor (followingFactor)*
;
followingFactor
: Operator=('*' | '/' | '%') factor
;
factor
: NUMBER # Factor_Number
| reference # Factor_Reference
| '(' arithmeticOperation ')' # Factor_InnerArithmeticOperation
;
/*
* Boolean Operators
*/
booleanOperation
: disjunction
;
disjunction
: conjunction (followingConjunction)*
;
followingConjunction
: Operator=OR conjunction
;
conjunction
: booleanComparison (followingBooleanComparison)*
;
followingBooleanComparison
: Operator=AND booleanComparison
;
booleanComparison
: booleanFactor (followingBooleanFactor)*
;
followingBooleanFactor
: Operator=(EQUALS | NOT_EQUALS) booleanFactor
;
booleanFactor
: BOOLEAN # BooleanFactor_Boolean
| reference # BooleanFactor_Reference
| negation # BooleanFactor_Negation
| arithmeticComparison # BooleanFactor_ArithmeticComparison
| '(' booleanOperation ')' # BooleanFactor_InnerBooleanOperation
;
arithmeticComparison
: LeftHandSide=arithmeticOperation Operator=(EQUALS | NOT_EQUALS | GREATER_THAN | GREATER_THAN_OR_EQUAL_TO | LESS_THAN | LESS_THAN_OR_EQUAL_TO) RightHandSide=arithmeticOperation
;
negation
: NOT booleanFactor
;
/*
* Conditionals
*/
ifPart
: IF '(' booleanOperation ')' statementSet
;
elseifPart
: ELSEIF '(' booleanOperation ')' statementSet
;
elsePart
: ELSE statementSet
;
/* --- Lexer Rules --- */
/*
* Comments
*/
SINGLE_LINE_COMMENT
: '##' TEXT? NL -> skip
;
MULTI_LINE_COMMENT
: '#*' (TEXT | NL)* '*#' -> skip
;
COMMENT_BLOCK
: '#**' (TEXT | NL)* '*#' -> skip
;
/*
* Directives
*/
BREAK
: '#break'
| '#{break}'
;
DEFINE
: '#define'
| '#{define}'
;
ELSE
: '#else'
| '#{else}'
;
ELSEIF
: '#elseif'
| '#{elseif}'
;
END
: '#end'
| '#{end}'
;
EVALUATE
: '#evaluate'
| '#{evaluate}'
;
FOREACH
: '#foreach'
| '#{foreach}'
;
IF
: '#if'
| '#{if}'
;
INCLUDE
: '#include'
| '#{include}'
;
MACRO
: '#macro'
| '#{macro}'
;
PARSE
: '#parse'
| '#{parse}'
;
SET
: '#set'
| '#{set}'
;
STOP
: '#stop'
| '#{stop}'
;
UNPARSED
: '#[['
;
UNPARSED_END
: ']]#'
;
/*
* Identifier
*/
DOLLAR
: '$' -> more
;
IDENTIFIER
: CHARACTER+ (CHARACTER | INTEGER | HYPHEN | UNDERSCORE)*
;
/*
* Boolean Values
*/
TRUE
: 'true'
;
FALSE
: 'false'
;
/*
* Boolean Operators
*/
EQUALS
: '=='
| 'eq'
;
NOT_EQUALS
: '!='
| 'ne'
;
GREATER_THAN
: '>'
| 'gt'
;
GREATER_THAN_OR_EQUAL_TO
: '>='
| 'ge'
;
LESS_THAN
: '<'
| 'lt'
;
LESS_THAN_OR_EQUAL_TO
: '<='
| 'le'
;
OR
: '||'
;
AND
: '&&'
;
NOT
: '!'
| 'not'
;
/*
* Literals
*/
BOOLEAN
: TRUE
| FALSE
;
NUMBER
: '-'? INTEGER
| '-'? INTEGER '.' INTEGER
;
/*
* Content
*/
RAW_TEXT
: ~[*#$]+
;
TEXT
: (ESC | SAFE_CODE_POINT)+
;
fragment ESC
: '\\' (["\\/#$!bftrn] | UNICODE)
;
fragment UNICODE
: 'u' HEX HEX HEX HEX
;
fragment HEX
: [0-9a-fA-F]
;
fragment SAFE_CODE_POINT
: ~["\\\u0000-\u001F]
;
/*
* Atomic elements
*/
CHARACTER
: [a-zA-Z]+
;
INTEGER
: [0-9]+
;
HYPHEN
: '-'
;
UNDERSCORE
: '_'
;
NL
: '\r'
| '\n'
| '\r\n'
;
WS
: ('\t' | ' ' | '\r' | '\n' | '\r\n')+ -> skip
;
What details am i missing here? What has to be done to actually parse velocity code?
Best Regards
Update:
I have changed these lexer rules.
DOLLAR
: '$'
;
RAW_TEXT
: ~[*#$]*
;
TEXT
: (ESC | SAFE_CODE_POINT)*?
;
fragment SAFE_CODE_POINT
: ~[$"\\\u0000-\u001F]
;
And now i'm getting this messages.
[0] line 1:4 mismatched input '{Name}.java\r\n' expecting {'!', '{', IDENTIFIER}
[0] line 2:8 mismatched input ' ( ' expecting '('
[0] line 2:12 mismatched input 'vertice in ' expecting {'!', '{', IDENTIFIER}
[0] line 2:24 mismatched input 'Vertices )\r\n' expecting {'!', '{', IDENTIFIER}
[0] line 3:3 mismatched input ' ( ' expecting '('
[0] line 3:7 mismatched input 'vertice.Type == "Class" )\r\npublic class ' expecting {'!', '{', IDENTIFIER}
[0] line 4:14 mismatched input 'vertice.Name {\r\n\t' expecting {'!', '{', IDENTIFIER}
[0] line 5:9 mismatched input ' ( ' expecting '('
[0] line 5:13 mismatched input 'edge in ' expecting {'!', '{', IDENTIFIER}
[0] line 5:22 mismatched input 'Edges )\r\n\t' expecting {'!', '{', IDENTIFIER}
[0] line 6:4 mismatched input ' ( ' expecting '('
[0] line 6:8 mismatched input 'edge.from == ' expecting {'!', '{', IDENTIFIER}
[0] line 6:22 mismatched input 'vertice.Name)\r\n\t' expecting {'!', '{', IDENTIFIER}
It helped, but the lexer is still stealing the $ symbol and why is it expecting a '{' character while the input starts with a '{' character? I will have a look at this problem.
Related
So, I'm trying to assign a method value to a var in a test program, I'm using a Decaf grammar.
The grammar:
// Define decaf grammar
grammar Decaf;
// Reglas LEXER
// Definiciones base para letras y digitos
fragment LETTER: ('a'..'z'|'A'..'Z'|'_');
fragment DIGIT: '0'..'9';
// Las otras reglas de lexer de Decaf
ID: LETTER (LETTER|DIGIT)*;
NUM: DIGIT(DIGIT)*;
CHAR: '\'' ( ~['\r\n\\] | '\\' ['\\] ) '\'';
WS : [ \t\r\n\f]+ -> channel(HIDDEN);
COMMENT
: '/*' .*? '*/' -> channel(2)
;
LINE_COMMENT
: '//' ~[\r\n]* -> channel(2)
;
// -----------------------------------------------------------------------------------------------------------------------------------------
// Reglas PARSER
program:'class' 'Program' '{' (declaration)* '}';
declaration
: structDeclaration
| varDeclaration
| methodDeclaration
;
varDeclaration
: varType ID ';'
| varType ID '[' NUM ']' ';'
;
structDeclaration:'struct' ID '{' (varDeclaration)* '}' (';')?;
varType
: 'int'
| 'char'
| 'boolean'
| 'struct' ID
| structDeclaration
| 'void'
;
methodDeclaration: methodType ID '(' (parameter (',' parameter)*)* ')' block;
methodType
: 'int'
| 'char'
| 'boolean'
| 'void'
;
parameter
: parameterType ID
| parameterType ID '[' ']'
| 'void'
;
parameterType
: 'int'
| 'char'
| 'boolean'
;
block: '{' (varDeclaration)* (statement)* '}';
statement
: 'if' '(' expression ')' block ( 'else' block )? #stat_if
| 'while' '('expression')' block #stat_else
| 'return' expressionOom ';' #stat_return
| methodCall ';' #stat_mcall
| block #stat_block
| location '=' expression #stat_assignment
| (expression)? ';' #stat_line
;
expressionOom: expression |;
location: (ID|ID '[' expression ']') ('.' location)?;
expression
: location #expr_loc
| methodCall #expr_mcall
| literal #expr_literal
| '-' expression #expr_minus // Unary Minus Operation
| '!' expression #expr_not // Unary NOT Operation
| '('expression')' #expr_parenthesis
| expression arith_op_fifth expression #expr_arith5 // * / % << >>
| expression arith_op_fourth expression #expr_arith4 // + -
| expression arith_op_third expression #expr_arith3 // == != < <= > >=
| expression arith_op_second expression #expr_arith2 // &&
| expression arith_op_first expression #expr_arith1 // ||
;
methodCall: ID '(' arg1 ')';
// Puede ir algo que coincida con arg2 o nada, en caso de una llamada a metodo sin parametro
arg1: arg2 |;
// Expression y luego se utiliza * para permitir 0 o más parametros adicionales
arg2: (arg)(',' arg)*;
arg: expression;
// Operaciones
// Divididas por nivel de precedencia
// Especificación de precedencia: https://anoopsarkar.github.io/compilers-class/decafspec.html
rel_op : '<' | '>' | '<=' | '>=' ;
eq_op : '==' | '!=' ;
arith_op_fifth: '*' | '/' | '%' | '<<' | '>>';
arith_op_fourth: '+' | '-';
arith_op_third: rel_op | eq_op;
arith_op_second: '&&';
arith_op_first: '||';
literal : int_literal | char_literal | bool_literal ;
int_literal : NUM ;
char_literal : '\'' CHAR '\'' ;
bool_literal : 'true' | 'false' ;
And the test program is as follows:
class Program
{
int factorial(int b)
{
int n;
n = 1;
return n+2;
}
void main(void)
{
int a;
int b;
b=0;
a=factorial(b);
factorial(b);
return;
}
}
The parse tree for this program looks as following, at least for the part I'm interested which is a=factorial(b):
This tree is wrong, since it should look like location = expression -> methodCall
The following tree is how it looks on a friend's implementation, and it should sort of look like this if the grammar was correctly implemented:
This is correctly implemented, or the result I need, since I want the tree to look like location = expression -> methodCall and not location = expression -> location. If I remove the parameter from a=factorial(b) and leave it as a=factorial(), it will be read correctly as a methodCall, so I'm not sure what I'm missing.
So my question is, I'm not sure where I'm messing up in the grammar, I guess it's either on location or expression, but I'm not sure how to adjust it to behave the way I want it to. I sort of just got the rules literally from the specification we were provided.
In an ANTLR rule, alternatives are matches from top to bottom. So in your expression rule:
expression
: location #expr_loc
| methodCall #expr_mcall
...
;
the generated parser will try to match a location before it tries to match a methodCall. Try swapping those two around:
expression
: methodCall #expr_mcall
| location #expr_loc
...
;
I am writing a parser for a scripting language, and using antlr 4.5.3 for the purpose.
grammar VSE;
chunk
: block* EOF
;
block
: var '=' exp
| functioncall
;
var
: NAME
| var '[' exp ']'
| var '.' var
;
exp
: number
| string
| var
| functioncall
| <assoc=right> exp exp //concat
;
functioncall
: NAME '(' (exp)? (',' exp)* ')'
| var '.' functioncall
;
string
: '"' (~('"' | '\\' | '\r' | '\n') | '\\' ('"' | '\\'))* '"'
;
NAME
: [a-zA-Z_][a-zA-Z_0-9]*
;
number
: INT | HEX | FLOAT
;
INT
: Digit+
;
HEX
: '0' [xX] [0-9a-fA-F]+
;
FLOAT
: Digit* '.' Digit+
;
Digit
: [0-9]
;
WS
: [ \t\u000C\r\n]+ -> skip
;
However, while testing it, I found a variable assignment like var = something followed by some function call in next line leads to a concat statement. (My concat statement is a variable followed by another like var = var1 var2) I understand that antlr is skipping ALL the new lines in favor of line continuation, but I'd like to add the condition that if there is a new line between two exps, it would treat them as two separate blocks instead of a concat statement. i.e.
var = var2
functioncall(var)
These should be two separate blocks instead of concat statement.
Is there any way to do this?
Does the following rule suitable for you?
block
: var '=' exp NEW_LINE
| functioncall NEW_LINE
;
NEW_LINE: '\r'? '\n'
WS
: [ \t]+ -> skip
;
In another case you should use Semantic Predicates or very unclear grammar.
We are developing a DSL, and we're facing some problems:
Problem 1:
In our DSL, it's allowed to do this:
A + B + C
but not this:
A + B - C
If the user needs to use two or more different operators, he'll need to insert parentheses:
A + (B - C) or (A + B) - C.
Problem 2:
In our DSL, the most precedent operator must be surrounded by parentheses.
For example, instead of using this way:
A + B * C
The user needs to use this:
A + (B * C)
To solve the Problem 1 I've got a snippet of ANTLR that worked, but I'm not sure if it's the best way to solve it:
sumExpr
#init {boolean isSum=false;boolean isSub=false;}
: {isSum(input.LT(2).getText()) && !isSub}? multExpr('+'^{isSum=true;} sumExpr)+
| {isSub(input.LT(2).getText()) && !isSum}? multExpr('-'^{isSub=true;} sumExpr)+
| multExpr;
To solve the Problem 2, I have no idea where to start.
I appreciate your help to find out a better solution to the first problem and a direction to solve the seconde one. (Sorry for my bad english)
Below is the grammar that we have developed:
grammar TclGrammar;
options {
output=AST;
ASTLabelType=CommonTree;
}
#members {
public boolean isSum(String type) {
System.out.println("Tipo: " + type);
return "+".equals(type);
}
public boolean isSub(String type) {
System.out.println("Tipo: " + type);
return "-".equals(type);
}
}
prog
: exprMain ';' {System.out.println(
$exprMain.tree == null ? "null" : $exprMain.tree.toStringTree());}
;
exprMain
: exprQuando? (exprDeveSatis | exprDeveFalharCaso)
;
exprDeveSatis
: 'DEVE SATISFAZER' '{'! expr '}'!
;
exprDeveFalharCaso
: 'DEVE FALHAR CASO' '{'! expr '}'!
;
exprQuando
: 'QUANDO' '{'! expr '}'!
;
expr
: logicExpr
;
logicExpr
: boolExpr (('E'|'OU')^ boolExpr)*
;
boolExpr
: comparatorExpr
| emExpr
| 'VERDADE'
| 'FALSO'
;
emExpr
: FIELD 'EM' '[' (variable_lista | field_lista) comCruzamentoExpr? ']'
-> ^('EM' FIELD (variable_lista+)? (field_lista+)? comCruzamentoExpr?)
;
comCruzamentoExpr
: 'COM CRUZAMENTO' '(' FIELD ';' FIELD (';' FIELD)* ')' -> ^('COM CRUZAMENTO' FIELD+)
;
comparatorExpr
: sumExpr (('<'^|'<='^|'>'^|'>='^|'='^|'<>'^) sumExpr)?
| naoPreenchidoExpr
| preenchidoExpr
;
naoPreenchidoExpr
: FIELD 'NAO PREENCHIDO' -> ^('NAO PREENCHIDO' FIELD)
;
preenchidoExpr
: FIELD 'PREENCHIDO' -> ^('PREENCHIDO' FIELD)
;
sumExpr
#init {boolean isSum=false;boolean isSub=false;}
: {isSum(input.LT(2).getText()) && !isSub}? multExpr('+'^{isSum=true;} sumExpr)+
| {isSub(input.LT(2).getText()) && !isSum}? multExpr('-'^{isSub=true;} sumExpr)+
| multExpr
;
multExpr
: funcExpr(('*'^|'/'^) funcExpr)?
;
funcExpr
: 'QUANTIDADE'^ '('! FIELD ')'!
| 'EXTRAI_TEXTO'^ '('! FIELD ';' INTEGER ';' INTEGER ')'!
| cruzaExpr
| 'COMBINACAO_UNICA' '(' FIELD ';' FIELD (';' FIELD)* ')' -> ^('COMBINACAO_UNICA' FIELD+)
| 'EXISTE'^ '('! FIELD ')'!
| 'UNICO'^ '('! FIELD ')'!
| atom
;
cruzaExpr
: operadorCruzaExpr ('CRUZA COM'^|'CRUZA AMBOS'^) operadorCruzaExpr ondeExpr?
;
operadorCruzaExpr
: FIELD('('!field_lista')'!)?
;
ondeExpr
: ('ONDE'^ '('!expr')'!)
;
atom
: FIELD
| VARIABLE
| '('! expr ')'!
;
field_lista
: FIELD(';' field_lista)?
;
variable_lista
: VARIABLE(';' variable_lista)?
;
FIELD
: NONCONTROL_CHAR+
;
NUMBER
: INTEGER | FLOAT
;
VARIABLE
: '\'' NONCONTROL_CHAR+ '\''
;
fragment SIGN: '+' | '-';
fragment NONCONTROL_CHAR: LETTER | DIGIT | SYMBOL;
fragment LETTER: LOWER | UPPER;
fragment LOWER: 'a'..'z';
fragment UPPER: 'A'..'Z';
fragment DIGIT: '0'..'9';
fragment SYMBOL: '_' | '.' | ',';
fragment FLOAT: INTEGER '.' '0'..'9'*;
fragment INTEGER: '0' | SIGN? '1'..'9' '0'..'9'*;
WS : ( ' '
| '\t'
| '\r'
| '\n'
) {skip();}
;
This is similar to not having operator precedence at all.
expr
: funcExpr
( ('+' funcExpr)*
| ('-' funcExpr)*
| ('*' funcExpr)*
| ('/' funcExpr)*
)
;
I think the following should work. I'm assuming some lexer tokens with obvious names.
expr: sumExpr;
sumExpr: onlySum | subExpr;
onlySum: atom ( PLUS onlySum )?;
subExpr: onlySub | multExpr;
onlySub: atom ( MINUS onlySub )? ;
multExpr: atom ( STAR atomic )? ;
parenExpr: OPEN_PAREN expr CLOSE_PAREN;
atom: FIELD | VARIABLE | parenExpr
The only* rules match an expression if it only has one type of operator outside of parentheses. The *Expr rules match either a line with the appropriate type of operators or go to the next operator.
If you have multiple types of operators, then they are forced to be inside parentheses because the match will go through atom.
I am trying to convert a LALR grammar to LL using ANTLR and I am running into a few problems. So far, I think converting the expressions into a Top-Down approach is straight forward to me. The problem is when I include Range (1..10) and (1.0..10.0) with floats.
I have tried to use the answer found here and somehow it is not even running correctly with my code, let alone solving a range of float, i.e. (float..float).
Float literal and range parameter in ANTLR
Attached is a sample of my grammar that just focuses on this issue.
grammar Test;
options {
language = Java;
output = AST;
}
parse: 'in' rangeExpression ';'
;
rangeExpression : expression ('..' expression)?
;
expression : addingExpression (('=='|'!='|'<='|'<'|'>='|'>') addingExpression)*
;
addingExpression : multiplyingExpression (('+'|'-') multiplyingExpression)*
;
multiplyingExpression : unaryExpression
(('*'|'/'|'div') unaryExpression)*
;
unaryExpression: ('+'|'-')* primitiveElement;
primitiveElement : literalExpression
| id ('.' id)?
| '(' expression ')'
;
literalExpression : NUMBER
| BOOLEAN_LITERAL
| 'infinity'
;
id : IDENTIFIER
;
// L E X I C A L R U L E S
Range
: '..'
;
NUMBER
: (DIGITS Range) => DIGITS {$type=DIGITS;}
| (FloatLiteral) => FloatLiteral {$type=FloatLiteral;}
| DIGITS {$type=DIGITS;}
;
// fragments
fragment FloatLiteral : Float;
fragment Float
: DIGITS ( options {greedy = true; } : '.' DIGIT* EXPONENT?)
| '.' DIGITS EXPONENT?
| DIGITS EXPONENT
;
BOOLEAN_LITERAL : 'false'
| 'true'
;
IDENTIFIER : LETTER (LETTER | DIGIT)*;
WS : ( ' '
| '\t'
| '\r'
| '\n'
) {$channel=HIDDEN;}
;
fragment LETTER : ('a'..'z' | 'A'..'Z' | '_') ;
fragment DIGITS: DIGIT+;
fragment DIGIT : '0'..'9';
fragment EXPONENT : ('e'|'E') ('+'|'-')? ('0'..'9')+ ;
Any reason why it is not even taking:
in 10;
or
in 10.0;
Thanks in advance!
The following things are not correct:
you're never matching a FloatLiteral in your literalExpression rule
in every alternative of NUMBER you're changing the type of the token, therefor a NUMBER token will never be created
Something like this should work for both 11..22 and 1.1..2.2:
...
literalExpression : INT
| BOOLEAN_LITERAL
| FLOAT
| 'infinity'
;
id : IDENTIFIER
;
// L E X I C A L R U L E S
Range
: '..'
;
INT
: (DIGITS Range)=> DIGITS
| DIGITS (('.' DIGITS EXPONENT? | EXPONENT) {$type=FLOAT;})?
;
BOOLEAN_LITERAL : 'false'
| 'true'
;
IDENTIFIER : LETTER (LETTER | DIGIT)*;
WS : ( ' '
| '\t'
| '\r'
| '\n'
) {$channel=HIDDEN;}
;
fragment LETTER : ('a'..'z' | 'A'..'Z' | '_') ;
fragment DIGITS: DIGIT+;
fragment DIGIT : '0'..'9';
fragment EXPONENT : ('e'|'E') ('+'|'-')? ('0'..'9')+ ;
fragment FLOAT : ;
To your question about handling (1.0 .. 10.0):
Notice that parser rule primitiveElement defines an alternative as '(' expression ')', but rule expression can never reach rule rangeExpression.
Consider redefining expression and rangeExpression like so:
expression : rangeExpression
;
rangeExpression : compExpression ('..' compExpression)?
;
compExpression : addingExpression (('=='|'!='|'<='|'<'|'>='|'>') addingExpression)*
;
This ensures that the expression rule sits above all forms of expressions and will work as expected in parentheses.
I've written a very simple grammar definition for a calculation expression:
grammar SimpleCalc;
options {
output=AST;
}
tokens {
PLUS = '+' ;
MINUS = '-' ;
MULT = '*' ;
DIV = '/' ;
}
/*------------------------------------------------------------------
* LEXER RULES
*------------------------------------------------------------------*/
ID : ('a'..'z' | 'A' .. 'Z' | '0' .. '9')+ ;
WHITESPACE : ( '\t' | ' ' | '\r' | '\n'| '\u000C' )+ { Skip(); } ;
/*------------------------------------------------------------------
* PARSER RULES
*------------------------------------------------------------------*/
start: expr EOF;
expr : multExpr ((PLUS | MINUS)^ multExpr)*;
multExpr : atom ((MULT | DIV)^ atom )*;
atom : ID
| '(' expr ')' -> expr;
I've tried the invalid expression ABC &* DEF by start but it passed. It looks like the & charactor is ignored. What's the problem here?
Actually your invalid expression ABC &= DEF hasn't been passed; it causes NoViableAltException.