zoukankan      html  css  js  c++  java
  • 五分钟介绍ANTLR 3

    翻译Antlr的内容来学习Antlr,还会让我不会睡觉,不觉得困。

    以一个简单的计算器开始,当作学习Antlr的一个例子。

    任何一个语言处理程序都有至少两部分:

    1、一个词法解释器:获得字符串流,将这个流按预先设定要的规则分割成一个个的token

    2、一个语法分析器:读token,根据规则翻译他们。

    让我们为一个简单的算数表达式定义一个规则:

    grammar SimpleCalc;
    
    add : NUMBER PLUS NUMBER;
    
    NUMBER : ('0'..'9')+ ;
    
    PLUS      : '+';

    这个例子包含两部分规则:NUMBER and PLUS ,和一个语法规则 add。词法规则常常以大写字母开头,语法规则以小写字母开头。

    • NUMBER 定义了包含0到9的字符的token,这些字符可以重复一次或一次以上
    • PLUS 定义了一个简单的字符token:+
    • add 定义了一个语法规则,这个语法表示希望接收一个NUMBER token,一个PLUS token,一个NUMBER token,并顺序固定。如果以不同的顺序将会触发错误消息。

    分析这个计算

    让我们接受更复杂的表达式,像1或1+2或1+2+3+4,这些表达式以一个数字开头,然后加上一个加法标志和一个数(有可能多于一次):

    add : NUMBER (PLUS NUMBER)*

    *表示0或多次

    如果你既想实现加法又想实现减法,你可以做一个小的调整:

    add : NUMBER ((PLUS | MINUS) NUMBER)*
    MINUS : '-';

    你可能已经猜到了,| 意味着“或者”,也就是“加”或者“减”。

    如果你希望语法分析完成算术表达式像1+2*3,有一个标准的递归方法来实现它:

    expr         : term ( ( PLUS | MINUS ) term )*;
    term         : factor ( ( MULT | DIV ) factor )*;
    factor       : NUMBER ;
    
    MULT  : '*' ;
    DIV   : '/' ;

    (计算机一个表达式,通常以expr开头)

    我们的语法是不能容忍空格的:当遇到空格,标签符,回车等它会给出警告。我们要告诉词法分析器丢弃任何它所找到的空格是安全的。

    首先,我们要定义空格:

    • 一个空格:‘ ’
    • 一个标签符是这样表示的:‘\t’
    • 新的一行是这样表示的:‘\n’
    • 一个回车符是这样表示的:‘r’
    • 一个换页符有一个十进制值12和一个十六进制值0C。Antlr用Unicode编码,所以我们将它定义为4个十六进制数字:‘\u000C’

    把这些放在一块,并用一个“or”连接,允许一个或多个一块出现,那么你会得到:

    WHITESPACE : ( '\t' | ' ' | '\r' | '\n' | '\u000C' )+;

    那么,如果我们写3 + 4*5这个表达式,词法分析器会生成 NUMBER WHITESPACE PLUS WHITESPAC NUMBER MULT NUMBER,而且这将导致语法分析器抱怨未知WHITESPACE标记。我们需要一种方法对于语法分析器,将他们隐藏起来。

     Antlr在词法分析器和语法分析器之间包含两种沟通渠道,默认渠道和隐藏渠道。语法分析器一次只听取一个渠道的内容,所以你可以用将它至于隐藏渠道的方法来隐藏一个标记。

    (可以有多于两种渠道而且语法分析器可以单独听取他们中的任一个,也可以从所有合并的渠道获取信息。这在你正在写一个文字处理工具的时候非常有用,这个文字处理工具需要解析出空白和注释的输出,而且让语法分析器忽略这些元素)

    对于连续不断的隐藏要求,你用设置这些token的$channel来隐藏他们。这要求你加一些大括号来在词法分析器中添加一点点代码。

    WHITESPACE : ( '\t' | ' ' | '\r' | '\n' | '\u000C' ) + { $channel = HIDDEN; };

    (如果你现在正在键盘上试图实现词法分析和语法分析的代码,而且正在词法分析器中搜寻 channel = HIDDEN

    ANTLR默认生成java代码。你将会在一分钟内学会怎么更改它)

    整理你的代码

    你可以用很多技术来让你的语法更具有可读性:

    1. 添加注释,比如 // 或者/*....*/
    2. 将你的简单token定义(单字符,单词等)收集到文件顶部的token中
    3. 考虑用fragment规则定义子部分的标记。一个fragment规则将不会自己生成标记,但可以被用作规则的一部分,来定义其余的标记。

    这是一个整理好的代码:

     1 grammar SipleCalc;
     2 
     3 tokens{
     4   PLUS     = '+' ;
     5   MINUS    = '-' ;
     6   MULT     = '*';
     7   DIV      = '/';
     8 }
     9 /*------------------------------------------------------------------
    10  * PARSER RULES
    11  *------------------------------------------------------------------*/
    12  
    13 expr    : term ( ( PLUS | MINUS )  term )* ;
    14  
    15 term    : factor ( ( MULT | DIV ) factor )* ;
    16  
    17 factor  : NUMBER ;
    18  
    19 /*------------------------------------------------------------------
    20  * LEXER RULES
    21  *------------------------------------------------------------------*/
    22  
    23 NUMBER  : (DIGIT)+ ;
    24  
    25 WHITESPACE : ( '\t' | ' ' | '\r' | '\n'| '\u000C' )+  { $channel = HIDDEN; } ;
    26  
    27 fragment DIGIT  : '0'..'9' ;

    这表明了通常模式:得到一个输入流,进行词法分析,得到标记流,进行语法分析,然后在语法分析中调用其中的方法。(每个语法规则在语法分析器中添加一个相应的方法)

  • 相关阅读:
    三地气温的典型相关分析
    android 使用 BroadcastReceiver 总结
    发布网站问题笔记
    Android 两个Activity 实现数据的来回传递
    input 标签屏蔽谷歌浏览器高亮显示
    javascript 获取当前html 标签的位置
    c# 四舍五入
    利用SQL的charindex实现字符串数组和Split函数
    ExtJs 一些常用的控件
    C#中return、break、continue的用法
  • 原文地址:https://www.cnblogs.com/zhengrui0452/p/2793337.html
Copyright © 2011-2022 走看看