ANTLR 语法设计 (2)

上文 中,就用到了选择模式,如下:

stat: expr NEWLINE # printExpr | ID '=' expr NEWLINE # assign | NEWLINE # blank ; expr: expr op=('*'|'http://www.likecs.com/') expr # MulDiv | expr op=('+'|'-') expr # AddSub | INT # int | ID # id | '(' expr ')' # parens ;

也就是说,当语法规则中有允许这样也允许那样的含义时,就能使用选择模式。

词法符号依赖模式

如果在某个语句中看到了某个符号,就必须在同一个语句中找到和它配对的另外一个符号。为表达出这种语义,在语法中,我们使用一个序列来指明所有配对的符号,通常这些符号会把其他元素分组或者包裹起来。

上文 中,就用到了词法符号依赖模式,如下:

/** A rule called init that matches comma-separated values between {...}. */ init : '{' value (',' value)* '}' ; // must match at least one value 嵌套模式

如果一条语法规则定义中的伪代码引用了它自身,就需要一条递归规则(自引用规则)。

上文 中,也用到了递归,如下:

expr: expr op=('*'|'http://www.likecs.com/') expr # MulDiv | expr op=('+'|'-') expr # AddSub | INT # int | ID # id | '(' expr ')' # parens ;

语言结构上的递归自然而然地使得语言规则发生了递归。

总结
语言模式 描述
序列模式   它是一个有限长度或者任意长度的序列,序列中的元素可以是词法符号或者子规则。序列模式的例子包括变量声明(类型后面紧跟着标识符)和整数序列,例子:
retr : 'RETR' INT NEWLINE ; // 匹配“关键字-整数-换行符”序列
 
带终止符的序列模式   它是一个任意长的、可能为空的序列,该序列由一个词法符号分隔开,通常是分号或者换行符,其中的元素可以是词法符号或者子规则。这样的例子包括类Java语言的语句集合和一些用换行符来分隔的数据格式。例子:
(statement ';')* // Java的语句集合
(row NEWLINE)* // 多行数据
 
带分隔符的序列模式   它是一个任意长的、可能为空的序列,该序列由一个词法符号分隔开,通常是逗号、分号或是句号,其中的元素可以是词法符号或者子规则。这样的例子包括函数定义中的参数表、函数调用时传递的参数表、某些语句之间有分隔符却无终止符的编程语言,以及目录名。例子:
expr (',' expr)* // 函数调用时传递的参数
( expr (',' expr)* )? // 函数调用时传递的参数是可选的
'http://www.likecs.com/'? name ('http://www.likecs.com/' name)* // 简化的目录名
stat ('.' stat)* // 若干个SmallTalk语句
 
选择模式   它是一组备选分支的集合。这样的例子包括不同种类的类型、语句、表达式或者XML标签。举例:
type : 'int' | 'float' ;
stat : ifstat | whilestat | 'return' expr ';' ;
expr : '(' expr ')' | INT | ID ;
tag : '<' Name attribute* '>' | '<' 'http://www.likecs.com/' Name '>' ;
 
词法符号依赖模式   一个词法符号需要和一个或者多个后续词法符号匹配。这样的例子包括配对的圆括号、花括号、方括号和尖括号。例子:
'(' expr ')' // 嵌套表达式
ID '[' expr ']' // 数组索引表达式
'{' stat* '}' // 花括号包裹的若干个语句
'<' ID (',' ID)* '>' // 泛型声明
 
嵌套模式   它是一种自相似的语言结构。这样的例子包括表达式、Java的内部类、嵌套的代码块以及嵌套的Python函数定义。例子:
expr : '(' expr ')' | ID ;
classDef : 'class' ID '{' (classDef | method | field)* '}' ;
 
常见的词法结构

和语法分析器一样,词法分析器也使用规则来描述种类繁多的语言结构。在ANTLR中,我们使用的是几乎完全相同的标记。唯一的差别在于,语法分析器通过输入的词法符号流来识别特定的语言结构,而词法分析器通过输入的字符流来识别特定的语言结构。

由于词法规则和文法规则的结构相似,ANTLR允许二者在同一个语法文件中同时存在。不过,由于词法分析和语法分析是语言识别过程中的两个不同阶段,我们必须告诉ANTLR每条规则对应的阶段。它是通过这种方式完成的:

词法规则以大写字母开头,而文法规则以小写字母开头。

例如,ID是一个词法规则名,而expr是一个文法规则名。

对于关键字、运算符和标点符号,我们无须声明词法规则,只需要在文法规则中直接使用单引号将它们括起来即可,例如'while'、'*',以及'++'。有些开发者更愿意使用类似MULT的词法规则来引用'*',以避免对其的直接使用。这样,在改变乘法运算符的时候,只需修改MULT规则,而无须逐个修改引用了MULT的文法规则。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zggpzw.html