﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-HONG-文章分类-antlr3</title><link>http://www.blogjava.net/HONG/category/41609.html</link><description>&lt;font color='white'&gt;不在乃知，乃在能行！&lt;/font&gt;</description><language>zh-cn</language><lastBuildDate>Tue, 08 Sep 2009 14:54:07 GMT</lastBuildDate><pubDate>Tue, 08 Sep 2009 14:54:07 GMT</pubDate><ttl>60</ttl><item><title>antlr笔记</title><link>http://www.blogjava.net/HONG/articles/294262.html</link><dc:creator>HONG</dc:creator><author>HONG</author><pubDate>Tue, 08 Sep 2009 02:49:00 GMT</pubDate><guid>http://www.blogjava.net/HONG/articles/294262.html</guid><wfw:comment>http://www.blogjava.net/HONG/comments/294262.html</wfw:comment><comments>http://www.blogjava.net/HONG/articles/294262.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/HONG/comments/commentRss/294262.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/HONG/services/trackbacks/294262.html</trackback:ping><description><![CDATA[ANTLR的语法文件使用扩展巴科斯范式EBNF描述<br />
<strong>巴科斯范式扩展符号 EBNF</strong><br />
() : 产生式组合<br />
?&nbsp; : 产生式出现0或1次<br />
*&nbsp; : 0或多次<br />
+&nbsp; : 1或多次<br />
.&nbsp;&nbsp; : 任意一个字符<br />
~&nbsp; : 不出现后面的字符<br />
..&nbsp; : 字符范围<br />
<br />
<br />
<strong>零散的概念</strong><br />
语法多义性: 语法设计最值得关注的问题。第一点是人的思维对语法描述理解的歧义，与语法解释器的实际结果不一致，例如上面提到的expr的问题。另外就是语法描述本身逻辑上存在多义性，即对同样的输入可以解释成多种结果，它们都符合语法描述的规则。<br />
<br />
lexer: 词法分析器，从输入字符流解析出词汇序列(tokens)。<br />
parser: 语法解析器，对词汇进行语法分析，生成语法树(抽象语法树AST)。<br />
EBNF的语法不区分词法分析和语法分析，对应的只有终结符、非终结符，终结符描述输入，非终结符描述输入所表达的树结构。ANTLR使用词法分析器识别终结符，使用语法分析器分析非终结符(生成的分析器代码文件有两个，一个是词法分析器***Lexer，一个是语法分析器***Parser)，并要求词法规则全部以大写开始，语法规则全部以小写开始。对每一个语法规则，最终都必须以词法规则结束，否则是一个无效语法，生成时会报错。<br />
<br />
ANTLR生成的分析器代码中，语法规则都会有一个同名的方法，而词法规则的名称则跟语法文件给出的不一样。如果需要使用这些词法规则，可取的方法之一是定义一个语法规则与之对应；另外就是定义一个符号表，例如ANTLR笔记1中示例1里面的tokens{...}。定义符号表的优点是会优先匹配符号表，例如一些关键字等，可以避免他们被其它规则匹配上。<br />
关于规则的定义顺序，语法文件中先出现的规则具有优先匹配的作用。<br />
<br />
<strong>ANTLR笔记1中示例1的简单说明</strong><br />
1. <span style="color: #000000">grammar&nbsp;SimpleCalc;，定义语法名称。语法文件(.g文件)</span>名称必须与这里指定的名称一致。默认情况生成的语法分析器类名为"语法名称"+Parser，词法分析器类名为"语法名称"+Lexer。<br />
2. <span style="color: #000000">options&nbsp;{...}，定义全局配置参数，设置ANTLR生成过程中的一些控制选项，示例中指定目标语言为C#。<br />
3. tokens {...}，定义全局的符号表。<br />
4. </span><span style="color: #000000">@members {...}，这里面给出的代码将放入到生成的语法分析器类中，作为分析器类的成员属性、方法等。<br />
&nbsp;&nbsp; 示例中为分析器添加了一个Main方法，省得再格外写一个测试类。<br />
&nbsp;&nbsp; Main方法先从命令行读取输入字符，将输入字符传给生成的词法分析器</span><span style="color: #000000">SimpleCalcLexer</span><span style="color: #000000">，得到词汇序列</span><span style="color: #000000">CommonTokenStream</span><span style="color: #000000">。接下来使用生成的语法分析器</span><span style="color: #000000">SimpleCalcParser</span><span style="color: #000000">对词汇序列进行分析，在生成语法树的过程中直接由expr()方法返回计算结果。<br />
5. 语法规则。<br />
&nbsp;&nbsp; 把语法规则中的{...}、[...]等相关ANTLR的Action去掉就是EBNF。<br />
&nbsp;&nbsp; ANTLR生成的语法解析器代码中，对应每个语法规则都会生成一个方法，这个方法完成对应语法规则的分析逻辑。</span><span style="color: #000000">{...}、[...]等就是我们自己的</span>recognizer、translator需要的一些额外控制(Action)，分析匹配的逻辑由ANTLR完成，我们添加的这些控制就是对匹配到的结果怎样进行处理，是生成一个语法树，再由其它程序对语法树进行翻译，还是直接结合ANTLR的分析过程进行翻译转换或计算处理等，由我们进行控制。示例中是直接进行计算求值。<br />
&nbsp;&nbsp; returns [...]告诉ANTLR生成的方法需要返回什么内容，[int value]表示返回值类型为int，名字叫做value，就是声明了一个变量，用它来返回。在方法体里面，我们通过{...}中的内容进行求值运算，并把结果设置给value。{...}我们可以看作是一个宏，或者是一个模板，在里面我们可以使用ANTLR在代码生成时内置的一些变量/对象，它们以$开始(象StringTemplate语法，但不需要对应的$进行闭合)，这些变量在代码生成过程中ANTLR为我们设置好。其它的代码保持不变，放入到方法的相应位置上。<br />
6. 词法规则。<br />
&nbsp;&nbsp; <span style="color: #000000">{&nbsp;</span><span style="color: #000000">$</span><span style="color: #000000">channel&nbsp;</span><span style="color: #000000">=</span><span style="color: #000000">&nbsp;HIDDEN</span><span style="color: #000000">;</span><span style="color: #000000">&nbsp;}。默认情况下ANTLR在词法分析器和语法分析器之间使用两个通道通讯，一个default和一个hidden。语法分析器监听default通道接收词汇序列，所以如果将某个词汇发送到hidden通道，这个词汇就会被语法分析器忽略掉。示例中将回车换行等空白字符都过滤掉，不进行语法分析。<br />
&nbsp;&nbsp; </span><span style="color: #000000">fragment: 对词法规则有效(我没有看到对语法规则有作用)，它在生成的语法树上不会有对应的节点，即可以这样理解，它是我们在语法中定义的一个宏，可以被其它语法规则调用，但它不会成为最终语法树上的节点。</span>
  <img src ="http://www.blogjava.net/HONG/aggbug/294262.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/HONG/" target="_blank">HONG</a> 2009-09-08 10:49 <a href="http://www.blogjava.net/HONG/articles/294262.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>