使用antlr-一元减号和消息链的简化smalltalk语法

使用antlr-一元减号和消息链的简化smalltalk语法,antlr,grammar,smalltalk,backtracking,unary-operator,Antlr,Grammar,Smalltalk,Backtracking,Unary Operator,我正在使用antlr编写简单的类似于smalltalk的语法。它是smalltalk的简化版,但基本思想是相同的(例如消息传递) 以下是我到目前为止的语法: grammar GAL; options { //k=2; backtrack=true; } ID : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')* ; INT : '0'..'9'+ ; FLOAT : (

我正在使用antlr编写简单的类似于smalltalk的语法。它是smalltalk的简化版,但基本思想是相同的(例如消息传递)

以下是我到目前为止的语法:

grammar GAL;

options {
    //k=2;
    backtrack=true;
}

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

INT :   '0'..'9'+
    ;

FLOAT
    :   ('0'..'9')+ '.' ('0'..'9')* EXPONENT?
    |   '.' ('0'..'9')+ EXPONENT?
    |   ('0'..'9')+ EXPONENT
    ;

COMMENT
    :   '"' ( options {greedy=false;} : . )* '"' {$channel=HIDDEN;}
    ;

WS  :   ( ' '
        | '\t'
        ) {$channel=HIDDEN;}
    ;

NEW_LINE
    :   ('\r'?'\n')
    ;

STRING
    :  '\'' ( ESC_SEQ | ~('\\'|'\'') )* '\''
    ;

fragment
EXPONENT : ('e'|'E') ('+'|'-')? ('0'..'9')+ ;

fragment
HEX_DIGIT : ('0'..'9'|'a'..'f'|'A'..'F') ;

fragment
ESC_SEQ
    :   '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\')
    |   UNICODE_ESC
    |   OCTAL_ESC
    ;

fragment
OCTAL_ESC
    :   '\\' ('0'..'3') ('0'..'7') ('0'..'7')
    |   '\\' ('0'..'7') ('0'..'7')
    |   '\\' ('0'..'7')
    ;

fragment
UNICODE_ESC
    :   '\\' 'u' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
    ;

BINARY_MESSAGE_CHAR
    :   ('~' | '!' | '@' | '%' | '&' | '*' | '-' | '+' | '=' | '|' | '\\' | '<' | '>' | ',' | '?' | '/')
        ('~' | '!' | '@' | '%' | '&' | '*' | '-' | '+' | '=' | '|' | '\\' | '<' | '>' | ',' | '?' | '/')?
    ;

// parser

program
    :   NEW_LINE* (statement (NEW_LINE+ | EOF))*
    ;

statement

    :   message_sending
    |   return_statement
    |   assignment
    |   temp_variables
    ;

return_statement
    :   '^' statement
    ;

assignment
    :   identifier ':=' statement
    ;

temp_variables
    :   '|' identifier+ '|'
    ;

object
    :   raw_object
    ;

raw_object
    :   number
    |   string
    |   identifier
    |   literal
    |   block
    |   '(' message_sending ')'
    ;

message_sending
    :   keyword_message_sending
    ;

keyword_message_sending
    :   binary_message_sending keyword_message?
    ;

binary_message_sending
    :   unary_message_sending binary_message*
    ;

unary_message_sending
    :   object (unary_message)*
    ;

unary_message
    :   unary_message_selector
    ;

binary_message
    :   binary_message_selector unary_message_sending
    ;

keyword_message
    :   (NEW_LINE? single_keyword_message_selector NEW_LINE? binary_message_sending)+
    ;

block 
    : 
      '[' (block_signiture

      )? NEW_LINE* 
      block_body

      NEW_LINE* ']'
    ;

block_body 
    :  (statement 

      )?
      (NEW_LINE+ statement 

      )*
    ;


block_signiture 
    : 
      (':' identifier

      )+ '|'
    ;

unary_message_selector
    :   identifier
    ;

binary_message_selector
    :   BINARY_MESSAGE_CHAR
    ;

single_keyword_message_selector
    :   identifier ':'
    ;

keyword_message_selector
    :   single_keyword_message_selector+
    ;

symbol
    :   '#' (string | identifier | binary_message_selector | keyword_message_selector)
    ; 

literal
    :   symbol block? // if there is block then this is method
    ;

number
    : /*'-'?*/
    ( INT | FLOAT )
    ;

string
    :   STRING
    ;

identifier
    :   ID
    ;
每个消息都将发送到同一个对象,在本例中为
obj
。应保持消息优先级(一元>二进制>关键字)

3。回溯

大多数语法都可以用
k=2
进行解析,但当输入如下所示时:

1 + 2
Obj message: 
    1 + 2
    message2: 'string'
rule
    options { k = 2; }
    : // rule definition
    ;
解析器尝试将Obj匹配为
单个关键字消息选择器
,并在令牌
消息
上引发
UnwantedTokenExcaption
。如果删除
k=2
并设置
backtrack=true
(就像我做的那样),一切都会正常工作。我如何消除回溯并获得期望的行为

另外,大多数语法都可以使用
k=1
进行解析,因此我尝试只为需要它的规则设置
k=2
,但这被忽略了。我是这样做的:

1 + 2
Obj message: 
    1 + 2
    message2: 'string'
rule
    options { k = 2; }
    : // rule definition
    ;
但直到我在全局选项中设置了k,它才起作用。我错过了什么


更新

从头开始编写语法不是理想的解决方案,因为我有很多依赖它的代码。此外,smalltalk的一些功能在设计上缺失了。这不是另一个smalltalk实现,smalltalk只是一个灵感

我非常乐意让一元负号在这样的情况下工作:
-1+2
2+(-1)
。像
2--1
这样的情况就不那么重要了

此外,消息链接应该尽可能简单。这意味着我不喜欢改变我正在生成的AST的想法

关于回溯-我可以接受,只是出于个人好奇在这里问

这是一个生成AST的小修改语法-也许它将有助于更好地理解我不想更改的内容。(临时变量可能会被删除,我还没有做出决定)

语法GAL; 选择权{ //k=2; 回溯=真; 语言=CS3; 输出=AST; } 代币{ 散列=“#”; 冒号=':'; 点='; 插入符号='^'; 管道=“|”; LBRACKET='['; RBRACKET=']'; LPAREN='('; RPAREN=')'; 赋值=':='; } //生成文件选项 @命名空间{GAL.Compiler} @lexer::命名空间{GAL.Compiler} //这将在ANTLR生成的代码中禁用CLSComplaint警告 @解析器::头{ //不要在[System.CLSCompliant(false)] #pragma警告禁用3021 } @lexer::头{ //不要在[System.CLSCompliant(false)] #pragma警告禁用3021 } ID:('a'、'z'|'a'、'z'|'a'('a'、'z'|'a'、'z'|'0'、'9'|'a')* ; INT:'0'..'9'+ ; 浮动 :('0'..'9')+'。('0'..'9')*指数? |“.”('0'..'9')+指数? |('0'..'9')+指数 ; 评论 :“”(选项{贪婪=错误;}:)*“{$channel=隐藏;}” ; WS:(“” |“\t” ){$channel=Hidden;} ; 新线 :(“\r”?“\n”) ; 一串 :“\'”(ESC| ~(“\\'\'\''\''\'')*“\” ; 片段 指数:('e'|'e')('+'|'-')?('0'..'9')+ ; 片段 十六进制数字:('0'..'9'|'a'..'f'|'a'..'f'); 片段 电子稳定控制系统 :“\\”(“b”“t”“n”“f”“r”“r”“\\”)“\”\”\“\”\”) |UNICODE_ESC |八进制 ; 片段 八进制 : '\\' ('0'..'3') ('0'..'7') ('0'..'7') | '\\' ('0'..'7') ('0'..'7') | '\\' ('0'..'7') ; 片段 UNICODE_ESC :“\\”“u”十六进制数字十六进制数字十六进制数字十六进制数字十六进制数字 ; 二进制消息字符 : ('~' | '!' | '@' | '%' | '&' | '*' | '-' | '+' | '=' | '|' | '\\' | '' | ',' | '?' | '/') ('~' | '!' | '@' | '%' | '&' | '*' | '-' | '+' | '=' | '|' | '\\' | '' | ',' | '?' | '/')? ; //分析器 公共程序返回[AstProgram] :{$program=new AstProgram();} 新线* (声明(新线+| EOF) {$program.AddStatement($statement.stmt);} )* ; 语句返回[AstNode stmt] :信息发送 {$stmt=$message_sending.messageSending;} |return\u语句 {$stmt=$return_statement.ret;} |分配 {$stmt=$assignment.assignment;} |温度变量 {$stmt=$temp_variables.tempVars;} ; return\语句返回[AstReturn ret] :插入符号语句 {$ret=new AstReturn($CARET,$statement.stmt);} ; 分配返回[分配分配分配] :点式表达式赋值语句 {$assignment=new astasignment($dotterd_expression.dotteexpression,$ASSIGN,$statement.stmt);} ; temp_变量返回[AstTempVariables tempVars] :p1=管道 {$tempVars=新的AstTempVariables($p1);} (标识符) {$tempVars.AddVar($identifier.identifier);} )+ p2=管道 {$tempVars.EndToken=$p2;} ; 对象返回[AstNode obj] :号码 {$obj=$number.number;} |串 {$obj=$string.str;} |虚线表达式 {$obj=$dotterd_expression.dottedExpression;} |文字的 {$obj=$literal.literal;} |挡块 {$obj=$block.block;} |LPAREN消息\u发送RPAREN {$obj=$message_sending.messageSending;} ; 消息发送返回[AstKeywordMessageSending] :关键字\u消息\u发送 {$messageSending=$keyword_message_sending.keywordMessageSending;} ; 关键字消息发送返回[AstKeywordMessageSending关键字消息发送] :二进制消息发送 {$keywordMessageSending=new AstKeywordMessageSending($binary_message_sending.binaryMessageSending);} (关键字)信息 {$keywordMessageSending=$keywordMessageSending.NewMessage($keyword_message.keywordMessage);} )? ; 二进制消息发送返回[AstBinaryMessageSending bi]