//#!/usr/bin/runantlr
header {
#
# LiberMate
#
# Copyright (C) 2009 Eric C. Schug
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
__author__ = "Eric C. Schug (schugschug@gmail.com)"
__copyright__ = "Copyright (c) 2009 Eric C. Schug"
__license__ = "GNU General Public License"
__revision__ = "$Id$"
import traceback
}
header "__init__" {
# gets inserted in the __init__ method of each of the generated Python
# classes
#
self.paren_count=0
self.brack_count=0
self.string_ok=True
self.gobble_space=True
}
options {
language = "Python";
}
class MatlabParser extends Parser;
options {
buildAST = true;
k=2;
}
tokens {
EXPR;
DECL;
FUNCTION;
IFBLOCK;
BLOCK;
BCOLON;
SIGN_PLUS;
SIGN_MINUS;
VAR;
SCOPE;
DOT;
ARGUMENTS;
CONTINUATION;
END;
ARRAY_END;
BREAK="break";
CONT="continue";
RETURN="return";
RETURN_VARS;
COMMAND;
LAMBDA;
ALLELEMENTS;
TRANS;
CELL;
MATRIX;
COLUMN_JOIN;
ROW_JOIN;
FLOAT;
COMPLEX;
ASSERT="assert";
GLOBAL="global";
FUNCTION_ARGS;
BRACE_ARGS;
PAREN_ARGS;
}
sp : SPACE! ;
script:
{True}? ((COMMENT)? NEWLINE!)*
( (function)+ | block) EOF!;
function: "function"! {self.new_scope()} (sp)? (funcreturn)? noun (funcargs)? (ender)+ block (END! (sp)? (ender)+)?
{#function = #([FUNCTION,"function"],self.get_scope(),#function);}
;
funcreturn: LBRACK!
(a:NAME {self.as_var(#a)}
( (sp | COMMA! (sp)?) b:NAME {self.as_var(#b)})* )?
RBRACK! (sp)? r:ASSIGN^ {#r.setType(RETURN_VARS)} (sp)?
| c:NAME {self.as_var(#c)} (sp)? d:ASSIGN^ {#d.setType(RETURN_VARS)} (sp)?
;
funcargs: p:LPAREN^ {#p.setType(FUNCTION_ARGS)}
(a:NAME {self.as_var(#a)} ( (sp)? COMMA! (sp)? b:NAME {self.as_var(#b)})* )? RPAREN! (sp)?
;
block : ( command_or_statement (ender)+ )* {#block = #([BLOCK,"block"],#block);} ;
command_or_statement
:! GLOBAL (a:NAME {self.as_global(#a)} )+
| (NAME noun)=> command
| "if"^ (sp)? t:expr (ender)+ tb:block (elseifblock)* (elseblock)? END! (sp)?
| "while"^ (sp)? expr (ender)+ block END! (sp)?
| "for"^ (sp)? b:NAME {self.as_var(#b)} (sp)? ASSIGN! (sp)? expr (ender)+ block END!
| "try"^ (sp)? ender block (catchblock)? END! (sp)?
| "switch"^ (sp)? expr (sp)? (ender)+ (caseblock)+ (otherwiseblock)? END! (sp)?
| substatement
| SPACE!
;
catchblock : "catch"^ (sp)? (ender)+ block ;
caseblock : "case"^ (sp)? expr (sp)? (ender)+ block ;
elseifblock : "elseif"^ (sp)? expr (ender)+ block ;
otherwiseblock : "otherwise"^ (sp)? (ender)+ block ;
elseblock : a:"else"^ (sp)? ((ender)+ block | substatement (ender)+) ;
command : a:NAME^ {#a.setType(COMMAND)} (b:NAME {#b.setType(STRING)})* ;
substatement
:
(lhs (SPACE)? ASSIGN )=> lhs (sp)? ASSIGN^ expr
| BREAK (sp)?
| CONT (sp)?
| RETURN (sp)?
| expr ;
ender : (COMMENT)? NEWLINE!
| SEMI!
| COMMA!
;
lhs : LBRACK^ (a:NAME {self.as_var(#a)}
( (sp | COMMA! (sp)?) b:NAME {self.as_var(#b)})* )? RBRACK!
| reference_lhs (DOT^ {self.is_dot=True} reference_lhs {self.is_dot=False} )*
;
reference_lhs:
c:NAME {self.as_var(#c)}
(brace_arglist {#reference_lhs = #([BRACE_ARGS],#reference_lhs);} )?
(paren_arglist {#reference_lhs = #([PAREN_ARGS],#reference_lhs);} )?
;
paren_arglist
: a:LPAREN! {
self.inside_args=True
pgobble_space=self.gobble_space
self.gobble_space=True
} arg_list RPAREN! {
self.inside_args=False
self.gobble_space=pgobble_space
}
;
brace_arglist
: LBRACE! {
self.inside_args=True
pgobble_space=self.gobble_space
self.gobble_space=True
} arg_list RBRACE! {
self.inside_args=False
self.gobble_space=pgobble_space
}
;
arg_list : (expr | a:COLON {#a.setType(ALLELEMENTS)} )
( COMMA! (expr | b:COLON {#b.setType(ALLELEMENTS)} ) )* ;
expr : expr_1
| expr_at expr_1 {#expr = #([LAMBDA],#expr);}
;
expr_at : ATPAREN^
a:NAME {self.as_var(#a)} ( COMMA! (sp)? b:NAME {self.as_var(#b)})* (sp)?
RPAREN! (sp)?
;
expr_1 : expr_2 ( OROR^ expr_2 )* ;
expr_2 : expr_3 ( ANDAND^ expr_3 )* ;
expr_3 : expr_4 ( OR^ expr_4 )* ;
expr_4 : expr_5 ( AND^ expr_5 )* ;
expr_5 : expr_6
( (EQUAL^ | NOT_EQUAL^ | LESS_THAN^ | LESS_OR_EQUAL^
| GREATER_THAN^ | GREATER_OR_EQUAL^ ) expr_6 )* ;
expr_6 : expr_7 ( COLON^ expr_7 ( COLON! expr_7 )? )?
;
expr_7 : expr_8 ( (PLUS^ | MINUS^) expr_8 )* ;
expr_8 : expr_9 ( (STAR^ | DIV^ | BACKDIV^ | DOTSTAR^ | DOTDIV^ | DOTBACKDIV^ ) expr_9 )* ;
expr_9 : (NOT^ | p:PLUS^ {#p.setType(SIGN_PLUS)}| m:MINUS^ {#m.setType(SIGN_MINUS)} )* expr_10 ;
expr_10 : expr_11 ( (EXP^ | DOTEXP^ ) expr_11 )* ;
expr_11
: AT^ NAME
| expr_11a
;
expr_11a : expr_12 ({self.gobble_space}? SPACE!)? ( TRANS^ | DOTTRANS^ )? ;
expr_12
: NUMBER
| INT
| FLOAT
| COMPLEX
| reference (DOT^ {self.is_dot=True} reference {self.is_dot=False} )*
| MATCHVAR
| ASSERT^ LPAREN! {
pgobble_space=self.gobble_space
self.gobble_space=True // disable automatic space skipping
} expr COMMA! expr RPAREN! {self.gobble_space=pgobble_space}
| b:STRING
| LPAREN!
{
pgobble_space=self.gobble_space
self.gobble_space=True // disable automatic space skipping
}
expr
RPAREN! {self.gobble_space=pgobble_space}
| c:LBRACK^
{
#c.setType(MATRIX)
pgobble_space=self.gobble_space
self.gobble_space=False // disable automatic space skipping
}
(semiblock)? RBRACK! {self.gobble_space=pgobble_space}
| ARRAY_END
| d:LBRACE^
{
#d.setType(CELL)
pgobble_space=self.gobble_space // disable automatic space skipping
self.gobble_space=False
}
(semiblock)? RBRACE! {self.gobble_space=pgobble_space}
;
reference:
a:NAME {self.var_lookup(#a)}
(brace_arglist {#reference = #([BRACE_ARGS],#reference);} )?
( paren_arglist {#reference = #([PAREN_ARGS],#reference);} )?
;
semiblock : {g=False} commablock (( (NEWLINE!)+ | SEMI! (NEWLINE!)* ) commablock {g=True} )*
{if g: #semiblock = #([ROWJOIN],#semiblock);}
;
commablock : expr_1 (( (SPACE!) | COMMA! (sp)? ) expr_1 )* {#commablock = #([COLUMNJOIN],#commablock);}
;
noun : a:NAME {self.var_lookup(#a)};
class MatlabLexer extends Lexer;
options {
k=3;
}
STRING : {self.string_ok}? '\'' (~('\''| '\n') | '\'' '\'' )* '\'' {self.string_ok=False}
| '\'' {$setType(TRANS);} {$setType(TRANS);}
;
COMMENT : '%' (~('\r' | '\n'))* ; // {$setType(Token.SKIP);};
//NONWHITE : ~('%' | ' ' | '\t' | '\n' | '\r') ;
SPACE : (' ' | '\t')+ { if self.brack_count<=0: $setType(Token.SKIP);}
;
//WS : (' ' | '\t' | '\n' | '\r')+ /* {$setType(Token.SKIP);} how to automatic skip */ ;
//CONTINUATION : "..."; // (' ' | '\t' | '\r')* '\n' ;
//protected
//DIGITS : (DIGIT)+ ;
NUMBER
: (DIGIT)+ {$setType(INT)} ('.' Exponent | ('.' ((DIGIT)+ (Exponent)?)? | Exponent) {$setType(FLOAT)})? ('i'|'I'| 'j'|'J' {$setType(COMPLEX)})? {self.string_ok=False}
| ('.' DIGIT)=> '.' (DIGIT)+ (Exponent)? ('i'|'I'| 'j'|'J')? {self.string_ok=False}
| ('.' '.')=> "..." (SPACE)? (COMMENT)? NEWLINE {$setType(Token.SKIP);}
| '.' {$setType(DOT);} {self.string_ok=False}
;
protected
Exponent
: ('e' | 'E') ( '+' | '-' )? (DIGIT)+
;
//COMPLEX : INT ('i'|'j'|'J') | FLOAT ('i'|'I'| 'j'|'J')
// ;
NAME: ( 'a' .. 'z' | 'A' .. 'Z' | '_')
( 'a' .. 'z' | 'A' .. 'Z' | '_' | DIGIT )*
{
if $getText == "end":
if self.paren_count:
$setType(ARRAY_END);
else:
$setType(END);
if $getText in ["if","case","while","else","elseif","try","otherwise","catch"]:
self.string_ok=True
else:
self.string_ok=False
}
;
MATCH: '?' ( 'a' .. 'z' | 'A' .. 'Z' | '_')
( 'a' .. 'z' | 'A' .. 'Z' | '_' | DIGIT )*
{
if $getText == "end":
if self.paren_count:
$setType(ARRAY_END);
else:
$setType(END);
if $getText in ["if","case","while","else","elseif","try","otherwise","catch"]:
self.string_ok=True
else:
self.string_ok=False
}
;
ATPAREN : '@' '(' {self.paren_count+=1} {self.string_ok=False};
AND : '&' (SPACE)? {self.string_ok=True};
ANDAND : "&&" (SPACE)? {self.string_ok=True};
ASSIGN : '=' (SPACE)? {self.string_ok=True};
AT : '@' {self.string_ok=False};
BACKDIV : "\\" (SPACE)? {self.string_ok=True};
COLON : ':' (SPACE)? {self.string_ok=True};
COMMA : ',' (SPACE)? {self.string_ok=True};
//DEC : "--" {self.string_ok=True};
DIV : '/' (SPACE)? {self.string_ok=True};
//DOT : '.' {self.string_ok=True};
DOTTRANS : ".'" {self.string_ok=True};
DOTBACKDIV : ".\\" (SPACE)? {self.string_ok=True};
DOTDIV : "./" (SPACE)? {self.string_ok=True};
DOTEXP : ".^" (SPACE)? {self.string_ok=True};
DOTSTAR : ".*" (SPACE)? {self.string_ok=True};
EQUAL : "==" (SPACE)? {self.string_ok=True};
EXP : '^' (SPACE)? {self.string_ok=True};
GREATER_OR_EQUAL : ">=" (SPACE)? {self.string_ok=True};
GREATER_THAN : '>' (SPACE)? {self.string_ok=True};
LBRACK : '[' (SPACE)? {self.string_ok=True} {self.brack_count+=1};
LBRACE : '{' (SPACE)? {self.paren_count+=1} {self.string_ok=True};
LESS_OR_EQUAL : "<=" (SPACE)? {self.string_ok=True};
LESS_THAN : '<' (SPACE)? {self.string_ok=True};
//LOGICAL_NOT: '!' {self.string_ok=True};
OROR : "||" (SPACE)? {self.string_ok=True};
LPAREN : '(' (SPACE)? {self.paren_count+=1} {self.string_ok=True};
MINUS : '-' (SPACE)? {self.string_ok=True};
NOT : '~' (SPACE)? {self.string_ok=True};
NOT_EQUAL : "~=" (SPACE)? {self.string_ok=True};
OR : '|' (SPACE)? {self.string_ok=True};
PLUS : '+' (SPACE)? {self.string_ok=True};
RBRACK : ']' {self.string_ok=False} {self.brack_count-=1};
RBRACE : '}' {self.paren_count-=1} {self.string_ok=False};
RPAREN : ')' {self.paren_count-=1} {self.string_ok=False};
SEMI : ';' (SPACE)? {self.string_ok=True};
STAR : '*' (SPACE)? {self.string_ok=True};
//TRANS : '\'' {self.string_ok=False};
// keywords
//FUNCTION : "function" ;
//IF : "if" ;
//ELSEIF : "elseif" ;
//ELSE : "else" ;
//END : "end" ;
//SWITCH : "switch" ;
//TRY : "try" ;
//FOR : "for" ;
//WHILE : "while" ;
//OTHERWISE : "otherwise" ;
//CATCH : "catch" ;
//CASE : "case" ;
NEWLINE : ('\n' {$newline } | '\r' )+ (SPACE)? {self.string_ok=True};
//fhandle = @(arglist) expr
protected
DIGIT : '0' .. '9' ;
class Mat2Py extends TreeParser;
script returns [sstr]
{
sstr=""
//print "in script"
cc=[]
xx=""
ax=""
}
: ( g=function {cc.append(g)} )+ {sstr+="\n\n".join(cc)}
| ax=comment b=script {sstr=ax+b}
| h=block[""] {sstr+=h}
;
function returns [sstr]
{
sstr=""
//print "in function"
cc=[]
xx=""
ax=""
self.returnval=""
}
:#(FUNCTION {self.incr()} e:SCOPE (a=funcreturn {self.returnval=a} )? b:NAME c=funcargs d=block[""])
{
k=self.nl+"# Local Variables: "+e.getText()+self.nl+d+self.nl+"return ["+self.returnval+"]"
self.decr()
sstr=self.indent+"def "+b.getText()+c+":"+self.nl+k
}
;
comment returns [sstr]
{
sstr=""
//print "in comment"
cc=[]
}
: (a:COMMENT {cc.append("#"+a.getText())})+ {sstr=self.nl.join(cc)+self.nl}
//{print sstr}
;
funcreturn returns [sstr]
{
sstr=""
cc=[]
//print "in funcreturn"
}
: #(RETURN_VARS (a:VAR {cc.append(a.getText()) })+ ) {sstr=", ".join(cc)}
;
block[ptoken] returns [sstr]
{
sstr=""
cc=[]
c=None
self.ptoken=ptoken
//print "in block", ptoken
//self.tokenstack.append(_t)
enter=_t
if(_t and (_t.getType() not in [VAR,EXPR])):
self.is_simple_rhs=False
//if(_t):
// print "in block",_tokenNames[_t.getType()],_t.getText(),self.is_simple_rhs
sys.stdout.flush()
}
: #(BLOCK (g=block[ptoken] {if(g): cc.append(g)})* )
{
//print "block join ~"+self.indent+"~block",len(self.nl), len(cc)
sstr=self.nl.join(cc)
//print sstr
}
| #("if" {self.incr()} a=block[""] b=block[""] {self.decr()} (g=block[""] {cc.append(g)})* )
{
//print "if"
sstr="if "+a+":"+self.nl+" "+b+self.nl+self.nl.join(cc)+self.nl
}
| #("elseif" {self.incr()} aexpr=block[""] (g=block[""] {cc.append(g)})? )
{
sstr="elif "+aexpr+":"+self.nl+self.nl.join(cc)+self.nl
self.decr()
}
| #("else" {self.incr()} (g=block[""] {cc.append(g)})? )
{
//print "else"
sstr="else:"+self.nl+self.nl.join(cc)+self.nl
self.decr()
}
| #("for" {self.incr()} anoun=block[""] bexpr=block[""] cblock=block[""])
{
sstr="for "+anoun+" in "+bexpr+":"+self.nl+cblock+self.nl
self.decr()
}
| #("while" {self.incr()} aexpr=block[""] bblock=block[""])
{
sstr="while "+aexpr+":"+self.nl+bblock+self.nl
self.decr()
}
| #("try" {self.incr()} ablock=block[""] (bblock=block[""]))
{
sstr="try:"+self.nl+ablock
self.decr()
if(bblock):
sstr+=self.nl+bblock
sstr+=self.nl
}
| #("catch" {self.incr()} bblock=block[""])
{
sstr="except :"+self.nl+bblock
self.decr()
}
| #("switch" aexpr=block[""] (g=block[""] {cc.append(g)})* )
{
sstr="_switch_val="+aexpr+self.nl
sstr+="if False: # switch "+cc[0]+self.nl+" pass"+self.nl+ self.nl.join(cc)
sstr+=self.nl
}
| #("case" {self.incr()} aexpr=block[""] (g=block[""] {cc.append(g)})* )
{
sstr="elif _switch_val == "+aexpr+":"+self.nl+self.nl.join(cc)
//print "CASE"+sstr+"CASE"
self.decr()
}
| #("otherwise" {self.incr()} (g=block[""] {cc.append(g)})* )
{
sstr="else:"+self.nl+self.nl.join(cc)
self.decr()
}
| #(ANDAND a=block["and"] b=block["and"] ) {sstr=self.bop(" and ",a,b)}
| #(ASSIGN {self.is_lhs=True} a=block["="] {
self.is_lhs=False
self.is_simple_rhs=True
//print "Simple RHS"
} b=block["="] {self.is_simple_rhs=False}) {sstr=self.bop(" = ",a,b)}
| #(LAMBDA a=block[""] b=block[""] ) {sstr="lambda "+a+": "+b}
| #(ATPAREN (g=block[","] {cc.append(g)})* ) {sstr=", ".join(cc)}
| #(BACKDIV a=block[","] b=block[","] ) {sstr="linalg.solve("+a+", "+b+")"}
| #(COLON a=block[":"] b=block[":"] (c=block[":"])? )
{
sstr=self.colonop(a,b,c)
}
| #(COMMA (a=block[','] {cc.append(a)})+ ) {sstr=self.multiop(", ",cc)}
| #(DOT a=block['.'] ) {sstr=self.preop(".",a)}
// | #(LOGICAL_NOT a=block["not"]) {sstr=self.preop("not ",a)}
| #(NOT a=block["not"] ) {sstr=self.preop("not ",a)}
| #(SIGN_PLUS a=block[" +"] ) {sstr=self.preop("+",a)}
| #(SIGN_MINUS a=block[" -"] ) {sstr=self.preop("-",a)}
| #(DOTDIV a=block["/"] b=block["/"] ) {sstr=self.bop("/",a,b)}
| #(DOTEXP a=block["**"] b=block["**"] ) {sstr=self.bop("**",a,b)}
| #(DOTSTAR a=block["*"] b=block["*"] ) {sstr=self.bop("*",a,b)}
| #(MINUS a=block["-"] b=block["-"] ) {sstr=self.bop("-",a,b)}
| #(PLUS a=block["+"] b=block["+"] ) {sstr=self.bop("+",a,b)}
| #(EQUAL a=block["=="] b=block["=="] ) {sstr=self.bop(" == ",a,b)}
| #(NOT_EQUAL a=block["!="] b=block["!="] ) {sstr=self.bop(" != ",a,b)}
| #(GREATER_THAN a=block[">"] b=block[">"] ) {sstr=self.bop(" > ",a,b)}
| #(GREATER_OR_EQUAL a=block[">="] b=block[">="] ) {sstr=self.bop(" >= ",a,b)}
| #(LESS_OR_EQUAL a=block["<="] b=block["<="] ) {sstr=self.bop("<=",a,b)}
| #(LESS_THAN a=block["<"] b=block["<"] ) {sstr=self.bop("<",a,b)}
| #(OROR a=block["or"] b=block["or"] ) {sstr=self.bop(" or ",a,b)}
| #(LPAREN (g=block[""] {cc.append(g)} )* ) {sstr="("+", ".join(cc)+")"}
| #(ARGUMENTS (g=block[","] {cc.append(g)} )* ) {sstr=self.join_args(cc,ptoken=ptoken)}
| #(LBRACE (g=block[","] {cc.append(g)})* ) {sstr=self.join_args(cc,True) }
| #(MATRIX (g=block[","] {cc.append(g)})* ) {
if(cc):
sstr="array("+", ".join(cc)+")"
else:
sstr="array([])"
}
| #(CELL (g=block[","] {cc.append(g)})* ) {
if(cc):
sstr="cellarray("+", ".join(cc)+")"
else:
sstr="cellarray([])"
}
| #(EXPR (g=block[","] {cc.append(g)} )* ) {sstr=", ".join(cc)}
| #(ROWJOIN (a=block[","] {cc.append(a)} )* ) {sstr="r_["+", ".join(cc)+"]"}
| #(COLUMNJOIN (a=block[","] {cc.append(a)} )* ) {sstr="c_["+", ".join(cc)+"]"}
| #(AND a=block[','] b=block[','] ) {sstr="logical_and("+a+", "+b+")"}
| #(OR a=block[","] b=block[","] ) {sstr="logical_or("+a+", "+b+")"}
| #(STAR a=block[","] b=block[","] ) {sstr="dot("+a+", "+b+")"}
| #(DIV a=block[','] b=block[','] ) {sstr="matdiv("+a+", "+b+")"}
| #(DOTBACKDIV a=block[','] b=block[','] ) {sstr="matbackdiv("+a+", "+b+")"}
| #(EXP a=block[","] b=block[","] ) {sstr="matixpower("+a+", "+b+")"}
| #(AT a=block[ptoken] ) {sstr=a}
| BREAK {sstr="break"}
| CONT {sstr="continue"}
| RETURN {sstr="return ["+self.returnval+"]"}
| ARRAY_END {sstr="xend"}
| ALLELEMENTS {sstr=":"}
| #(TRANS a=block["."] ) {sstr=a+".conj().T"}
| #(DOTTRANS a=block["."] ) {sstr=a+".T"}
| #(q:COMMAND (a=block["NAME"] {cc.append("'"+a+"'")} )* ) {
sstr=self.Lookup(q.getText())+"("+"".join(cc)+")"
}
| #(i:NAME {self.nargin=0} (g=block["NAME"] {cc.append(g)} )* ) {
if(cc):
sstr=self.Lookup(i.getText())+"".join(cc)
else:
sstr=self.Lookup(i.getText())+"()"
}
| j:NEWLINE {sstr=j.getText()}
// In Matlab everything is a matrix
| k:NUMBER {sstr=k.getText()}
| u:INT {sstr=u.getText()+"."}
| v:FLOAT {sstr=v.getText()}
| w:COMPLEX {sstr=w.getText()}
| RBRACK {sstr=""}
| #(LBRACK (g=block[""] {cc.append(g)} )* ) {sstr="["+", ".join(cc)+"]"}
| m:RPAREN {sstr=""}
| p:STRING {sstr=p.getText().replace("''",r"\'")}
| #(r:VAR {self.in_var=True } (g=block["VAR"] { cc.append(g) } )* )
{
if(cc):
sstr=(r.getText())+"".join(cc)
else:
sstr=(r.getText())
if(self.is_simple_rhs):
sstr+=".copy()"
self.in_var=False
}
| t=comment {sstr=t} /* {print t} */ (g=block[ptoken] {sstr+=g})? // complains
;
funcargs returns [sstr]
{
sstr=""
cc=[]
//print "in funcargs"
}
: #(FUNCTION_ARGS (a:VAR {cc.append(a.getText())})* ) {sstr="("+", ".join(cc)+")" }
// | b:COMMENT {sstr="#"+b.getText()+"\n"} complains
;
default returns [sstr]
{sstr=""}
: #(b:NAME (c:NAME)? ) {
sstr=_t.getText()
//print "sdsdsd "+_t.toString()
}
| a:COMMENT {sstr="#"+a.getText()+"\n"}
;