[antlr-interest] Has anyone seen this kind of stack trace?

Alan D. Cabrera list at toolazydogs.com
Tue Nov 29 12:12:21 PST 2011


Lua.g:

/**
 * Copyright 2009-2011 (C) Alan D. Cabrera
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
grammar Lua;
options
{
    output=AST;
    backtrack=true;
}

tokens {
    ARGS;
    ARGSWITHSELF;
    ASSIGN;
    BLOCK;
    BREAK;
    CHUNK;
    ELSEIF;
    EXPLIST;
    DEREF;
    FOR;
    FORIN;
    FNAME;
    FNAMETHIS;
    FUNCALL;
    FUNCTION;
    FUNCBODY;
    IF;
    LOCAL;
    NAMELIST;
    NEGATE;
    NUMBER;
    PARAMETERS;
    PATH;
    REPEAT;
    RETURN;
    SINGLE;
    STRING;
    TBLCTOR;
    TBLFIELD;
    VAR;
    VARLIST;
    WHILE;
}

@header
{
package com.toolazydogs.lua4j;
}
@lexer::header
{
/**
 * Copyright 2009-2011 (C) Alan D. Cabrera
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.toolazydogs.lua4j;

import java.io.UnsupportedEncodingException;
}
@lexer::members
{
protected boolean isLongBracketOpen(int length)
{
    if (input.LA(1) != ']') return true;

    for (int i = 0; i != length; ++i)
    {
        if (input.LA(i + 2) != '=') return true;
    }

    return (input.LA(length + 2) != ']');
}

protected void matchLongBracketClose(int length) throws MismatchedTokenException
{
    StringBuilder builder = new StringBuilder();

    builder.append(']');
    for (int i = 0; i != length; ++i) builder.append('=');
    builder.append(']');

    match(builder.toString());
}

protected String toAscii(String... d) throws RecognitionException
{
    StringBuilder sb = new StringBuilder(d[0]);
    for (int i=1; i<d.length; i++) sb.append(d[i]);
        
    byte[] b = new byte[1];

    b[0] = (byte)Integer.parseInt(sb.toString());

    try
    {
        return new String(b, "ASCII");
    }
    catch (UnsupportedEncodingException e)
    {
        throw new RecognitionException();
    }
}
}

chunk
    : (stat ';'?)* (laststat ';'?)? -> ^(CHUNK stat* laststat?)
    ;

block
    : chunk
    ;

stat
    : varlist '=' explist -> ^(ASSIGN varlist explist)
    | functioncall
    | 'do' block 'end' -> block
    | 'while' exp 'do' block 'end' -> ^(WHILE exp block)
    | lc='repeat' block 'until' exp -> ^(REPEAT[$lc,"REPEAT"] block exp)
    | 'if' exp 'then' block 'end' -> ^(IF exp block)
    | 'if' exp 'then' ifblock=block 'else' elseblock=block 'end' -> ^(IF exp $ifblock $elseblock)
    | 'if' exp 'then' ifblock=block elseif+ 'end' -> ^(IF exp $ifblock elseif+)
    | 'if' exp 'then' ifblock=block elseif+ 'else' elseblock=block 'end' -> ^(IF exp $ifblock elseif+ $elseblock)
    | 'for' NAME '=' exp1=exp ',' exp2=exp ',' exp3=exp 'do' block 'end' -> ^(FOR NAME $exp1 $exp2 $exp3 block)
    | 'for' NAME '=' exp1=exp ',' exp2=exp 'do' block 'end' -> ^(FOR NAME $exp1 $exp2 block)
    | 'for' namelist 'in' explist 'do' block 'end' -> ^(FORIN namelist explist block)
    | 'function' funcname funcbody -> ^(FUNCTION funcname funcbody)
    | 'local' namelist ('=' explist)? -> ^(LOCAL namelist explist?)
    | 'local' 'function' NAME funcbody -> ^(LOCAL  ^(NAMELIST NAME) ^(EXPLIST funcbody))
    ;

elseif
    : ('elseif' exp 'then' block)+ -> ^(ELSEIF exp block)+
    ;

laststat
    : 'return' -> ^(RETURN)
    | 'return' explist -> ^(RETURN explist)
    | 'break' -> BREAK
    ;

funcname
@init{boolean hasThis = false;}
    : f=NAME ('.' p+=NAME)* (':' t=NAME {hasThis = true;})?
        -> {hasThis}? ^(FNAMETHIS $f $p* $t)
        -> ^(FNAME $f $p*)
    ;

varlist
    : var (',' var)* -> ^(VARLIST var+)
    ;

var
    : (varPrefix varDeref -> ^(DEREF varPrefix varDeref)) (vd=varDeref -> ^(DEREF $var $vd))*
    | NAME -> ^(VAR NAME)
    ;

varDeref
    : '[' exp ']' -> exp
    | '.' NAME -> ^(STRING NAME)
    ;

varPrefix
    : (NAME nameAndArgs-> ^(FUNCALL NAME nameAndArgs)) (naa=nameAndArgs -> ^(FUNCALL $varPrefix $naa))+
    | NAME nameAndArgs-> ^(FUNCALL NAME nameAndArgs)
    | '(' exp ')' -> ^(SINGLE exp)
    | NAME -> ^(VAR NAME)
    ;
    
prefixexp
    : (varOrExp nameAndArgs -> ^(FUNCALL varOrExp nameAndArgs)) (naa=nameAndArgs ->  ^(FUNCALL $prefixexp $naa))*
    | varOrExp
    ;

functioncall
    : (varOrExp nameAndArgs -> ^(FUNCALL varOrExp nameAndArgs)) (naa=nameAndArgs ->  ^(FUNCALL $functioncall $naa))*
    ;

varOrExp
    : var
    | '(' exp ')' -> ^(SINGLE exp)
    ;

nameAndArgs
    : args -> ^(ARGS args)
    | ':' NAME args -> ^(ARGSWITHSELF NAME args)
    ;

args
    : '(' ')' -> ^(EXPLIST)
    | '(' explist ')' -> explist
    | tableconstructor
    | string
    ;

namelist
    : NAME (',' NAME)* -> ^(NAMELIST NAME+)
    ;

explist
    : exp (',' exp)* -> ^(EXPLIST exp+)
    ;

exp
    : or ('or' or)+ -> ^('or' or+)
    | or
    ;

or
    : and ('and' and)+ -> ^('and' and+)
    | and
    ;

and
    : compare (compare_op^ compare)*
    ;

compare
    : concatenation ('..' concatenation)+ -> ^('..' concatenation+)
    | concatenation
    ;

concatenation
    : add_sub (add_sub_op^ add_sub)*
    ;

add_sub
    : b (b_op^ b)*
    ;

b
    : unary_op^ unary
    | unary
    ;

unary : atom ('^'^ atom)* ;

atom 	: 'nil'
        | 'false'
        | 'true'
        | number
        | string
        | function
        | prefixexp
        | tableconstructor
        | '...'
	;

unary_op : 'not' | '#' | '-' -> NEGATE ;

b_op : '*' | '/' | '%' ;

compare_op : '<' | '<=' | '>' | '>=' | '==' | '~=' ;

add_sub_op : '+' | '-' ;

function
    : 'function' funcbody -> funcbody
    ;

funcbody
    : '(' parlist? ')' block 'end' -> ^(FUNCBODY parlist? block)
	;

parlist
    : namelist -> ^(PARAMETERS namelist)
    | namelist ',' '...' -> ^(PARAMETERS namelist '...')
    | '...' -> ^(PARAMETERS '...')
    ;

tableconstructor
    : '{' fieldlist? '}' -> ^(TBLCTOR fieldlist?)
    ;

fieldlist
    : field (fieldsep! field)* fieldsep!?
    ;

field
    : '[' exp ']' '=' exp -> ^(TBLFIELD exp exp)
    | NAME '=' exp -> ^(TBLFIELD NAME exp)
    | exp -> ^(TBLFIELD exp)
    ;

fieldsep
    : ','
    | ';'
    ;

NAME
	: ('a'..'z' | 'A'..'Z' | '_') ('a'..'z' | 'A'..'Z' | '_' | '0'..'9')*
	;

number
    : INTEGER<IntNode>
    | FLOAT<FloatNode>
    | EXPONENT<FloatNode>
    | HEX<IntNode>
    ;

INTEGER
    : DIGIT+
    ;

FLOAT
    : DIGIT+ '.' DIGIT+
    ;

EXPONENT
    : (INTEGER | FLOAT) ('e' | 'E') '-'? INTEGER
    ;

HEX
    : '0x' ('0'..'9' | 'a'..'f')+
    ;

fragment
DIGIT : ('0'..'9') ;

string
    : s=NORMAL_STRING -> ^(STRING $s)
    | s=CHAR_STRING -> ^(STRING $s)
    | s=LONG_STRING -> ^(STRING $s)
    ;

NORMAL_STRING         
@init{StringBuilder sb = new StringBuilder();}
    :   
        '"' 
        ( escaped=ESCAPE_SEQUENCE { sb.append(getText()); } | 
          normal=~('"' | '\\')    { sb.appendCodePoint(normal); } )* 
        '"'     
        { setText(sb.toString()); }
    ;

CHAR_STRING         
@init{ StringBuilder sb = new StringBuilder(); }
    :   
        '\'' 
        ( escaped=ESCAPE_SEQUENCE { sb.append(getText()); } | 
             normal=~('\'' | '\\')    { sb.appendCodePoint(normal); } )* 
        '\''     
        { setText(sb.toString()); }
    ;

LONG_STRING
    : LONG_BRACKET
    ;

fragment
ESCAPE_SEQUENCE
    : '\\' 
    	( 'a'  { setText("\0007"); }
    	| 'b'  { setText("\b"); }
    	| 'f'  { setText("\f"); }
    	| 'n'  { setText("\n"); }
    	| 'r'  { setText("\r"); }
    	| 't'  { setText("\t"); }
    	| 'v'  { setText("\013"); }
    	| '"'  { setText("\""); }
    	| '\'' { setText("\'"); }
    	| '\\' { setText("\\"); }
    	)
    | ASCII_ESCAPE
    ;

fragment
ASCII_ESCAPE
    : '\\' d1=DIGIT d2=DIGIT d3=DIGIT { setText(toAscii(d1.getText(), d2.getText(), d3.getText())); }
    | '\\' d1=DIGIT d2=DIGIT { setText(toAscii(d1.getText(), d2.getText())); }
    | '\\' d1=DIGIT { setText(toAscii(d1.getText())); }
    ;

LONG_COMMENT
    : '--' LONG_BRACKET { skip(); }
    ;

fragment
LONG_BRACKET
@init { int n = 0; }
    : ('['('=' {++n;})*'[') ({isLongBracketOpen(n)}? => .)* 
    { 
        matchLongBracketClose(n);
        String text = getText().substring(n+2, getText().length()-(n+2));
        if (text.charAt(0) == '\n') text = text.substring(1, text.length());
        setText(text);
    }
    ;

LINE_COMMENT
    : '--' ~('\n' | '\r')* '\r'? '\n' { skip(); }
    ;

WS :  (' ' | '\t' | '\u000C') { skip(); } ;

NEWLINE : ('\r')? '\n' { skip(); } ;



More information about the antlr-interest mailing list