[antlr-interest] Embedding expressions in plain text -- how to?
Austin Hastings
Austin_Hastings at Yahoo.com
Sat Nov 10 17:07:32 PST 2007
Create an "outer" lexer that tokenizes your input as STRING PROGRAM
STRING ...
fragment OpenBrace : '${' ;
fragment CloseBrace: '}';
STRING: ( ~('$') | ('$' ~('{')))+ ;
PROGRAM: OpenBrace .* CloseBrace ;
Then parse the "PROGRAM" text elements as you like.
Note that if you want nested curly braces, you'll have to implement that
via a nested fragment that recurses on itself.
=Austin
Rob Greene wrote:
> How should I go about embedding an expression language in plain text.
> The expression is wrapped in '${' and '}' but may occur zero to many
> times within plain text. When in plain text, I want to keep the
> whitespace, but within the expression, it should be ignored.
>
> I've currently placed a boolean into a ThreadLocal and check that
> before calling skip() in my whitespace rule. But, that causes issues
> with the actual expressions.
>
> For instance, "${true}" returns Boolean.TRUE while "${ true }" returns
> a null. If I take out the test in WS, I can have those spaces within
> an expression, but the plain text loses all white space.
>
> I'm certain this is a simple fix, but I haven't a clue what to do!
>
> I'm using ANTLR 3.0.1.
>
> Thanks!
> -Rob
>
> /**
> * Language is the simple expression language used throughout the XML
> Template Engine.
> * General language constructs:
> * - functionName(argument, argument, ...)
> * - object.method.method
> * - 'string constant'
> * - "string constant"
> * - 1234.56
> * - true
> * - false
> * - null
> * - [ array, values, ... ]
> */
> grammar Language;
>
> /**
> * Use the embeddedExpression entry for expressions that are embedded
> within other
> * forms of text.
> * <p>
> * Note that unknown magic occurs because the plainText is somehow
> * glommed together into one string instead of character
> * by character.
> */
> embeddedExpression returns [List<Object> list]
> @init { list = new ArrayList<Object>(); }
> : ( '${' expression '}' { list.add($expression.value); }
> | plainText { list.add($plainText.value); }
> )*
> ;
>
> /**
> * Handle plain text that wraps around the expression.
> */
> plainText returns [String value]
> @init { ThreadState.current().ignoreWhitespace = false; }
> @after { ThreadState.current().ignoreWhitespace = true; }
> : '\\' '$' { $value = "$"; }
> | '\\' b=~('$') { $value = $b.text; }
> | a=~('$') { $value = $a.text; }
> ;
>
> /**
> * This is the bare expression evaluation. Evaluates one expression
> and returns
> * an Object.
> */
> expression returns [Object value]
> : function { $value = $function.value; }
> | constant { $value = $constant.value; }
> | reference { $value = $reference.value; }
> ;
>
> /**
> * Evaluate a function invocation, along with parameters and return
> the Object result.
> */
> function returns [Object value]
> : ID '(' arguments ')' { $value =
> Helper.invoke($ID.text,$arguments.value); }
> ;
> catch [LanguageException le] {
> emitErrorMessage(le.getMessage());
> throw new RuntimeException(le);
> }
>
> /**
> * Evaluate a constant value and return that value.
> */
> constant returns [Object value]
> : STRING { $value =
> $STRING.text.substring(1,$STRING.text.length()-1); }
> | NUMBER { $value = Double.valueOf($NUMBER.text); }
> | 'true' { $value = Boolean.TRUE; }
> | 'false' { $value = Boolean.FALSE; }
> | 'null' { $value = null; }
> | '[' arguments ']' { $value = $arguments.value; }
> ;
>
> /**
> * Evaluate an object reference and any nested evaluations and return
> that value.
> */
> reference returns [Object value]
> : a=ID { $value = Helper.find($a.text); }
> ('.' b=ID { $value = Helper.reflect($value,$b.text); }
> )*
> ;
> catch [LanguageException le] {
> emitErrorMessage(le.getMessage());
> throw new RuntimeException(le);
> }
>
> /**
> * A comma-separated argument list. Use for the function invocation
> and array list.
> */
> arguments returns [List<Object> value]
> @init { value = new ArrayList<Object>(); }
> : (a=expression { $value.add($a.value); }
> (',' b=expression { $value.add($b.value); }
> )* )?
> ;
>
> ID : Char (Char|Digit)*
> ;
> STRING : '"' ~('"')* '"'
> | '\'' ~('\'')* '\''
> ;
> NUMBER : ('-'|'+')? Digit+ ('.' Digit+)?
> ;
> WS
> : (' '|'\t'|'\r'|'\n')+ { if
> (!ThreadState.current().ignoreWhitespace) skip(); }
> ;
>
> fragment Char
> : 'a'..'z' | 'A'..'Z' | '_'
> ;
> fragment Digit
> : '0'..'9'
> ;
>
More information about the antlr-interest
mailing list