ANTLR:多语法支持

原创
2017/08/06 15:21
阅读数 115

多语法支持

有两个主要的应用场景

  • 同一种语言,不同版本语法解析起来不太一样,例如SQL,SQL有不同的版本
  • 同一种语法内,根据上下文的情况,同样的词法表达的语义不一样

多版本语法示例

这个示例里面有个关键的parser,定义了java5,而地下的enumDecl里面会判断是否是java5版本,假如不是,则会把enum部分给剪掉,在不同版本的解析中,ANTLR不会抛错,它只是不会执行被剪掉的那部分

EnumParser enumParser = new EnumParser(tokens);
enumParser.java5 = true;
grammar Enum;
@parser::members {public static boolean java5;}

prog:   (   stat 
        |   enumDecl
        )+
    ;

stat:   id '=' expr ';' {System.out.println($id.text+"="+$expr.text);} ;

expr
    :   id
    |   INT
    ;

enumDecl
    :   {java5}? 'enum' name=id '{' id (',' id)* '}'
        {System.out.println("enum "+$name.text);}
    ;

id  :   ID
    |   {!java5}? 'enum'
    ;
    
ID  :   [a-zA-Z]+ ;
INT :   [0-9]+ ;
WS  :   [ \t\r\n]+ -> skip ;

版本强制校验

上一种做法即使语法不兼容,ANTLR只是剪切掉后续的执行步骤,而不会报任何错误,这种做法,假如语法版本不兼容,在语法解析过程就会报错

留意一下lexer和param的区别,lexer设置后是不能改的,pram的则是可以修改的

grammar Enum2;
@lexer::members {public static boolean java5 = false;}

prog:   (   stat 
        |   enumDecl
        )+
    ;

stat:   ID '=' expr ';' {System.out.println($ID.text+"="+$expr.text);} ;

expr:   ID
    |   INT
    ;

// No predicate needed here because 'enum' token undefined if !java5
enumDecl
    :   'enum' name=ID '{' ID (',' ID)* '}'
        {System.out.println("enum "+$name.text);}
    ;

ENUM:   'enum' {java5}? ; // must be before ID
ID  :   [a-zA-Z]+ ;


INT :   [0-9]+ ;
WS  :   [ \t\r\n]+ -> skip ;

歧义语法处理

一般语法中出现这种情况,都是出现了bug。。当然也有其他情况的啦,以函数和类型转换为例,函数的调用是T(x),类型转换也可以写成T(x),处理的思路和版本号的思路类似

grammar PredCppStat;

@parser::header {
import java.util.*;
}

@parser::members {
Set<String> types = new HashSet<String>() {{add("T");}};
boolean istype() { return types.contains(getCurrentToken().getText()); }
}

stat:   decl ';'  {System.out.println("decl "+$decl.text);}
    |   expr ';'  {System.out.println("expr "+$expr.text);}
    ;

decl:   ID ID                         // E.g., "Point p"
    |   {istype()}? ID '(' ID ')'     // E.g., "Point (p)", same as ID ID
    ;

expr:   INT                           // integer literal
    |   ID                            // identifier
    |   {!istype()}? ID '(' expr ')'  // function call
    ;

ID  :   [a-zA-Z]+ ;
INT :   [0-9]+ ;
WS  :   [ \t\n\r]+ -> skip ;
展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部