编译原理——从if then else看使用二义性文法

      在研究语法分析器时,大部分语法分析器都期望文法是无二义性的,否则,我们就不能为一个句子唯一地选定语法分析树。但是在某种情况下,使用经过精心选择的二义性文法可以带来方便。此时需要使用消二义性规则来“抛弃”不想要的语法分析树,只为每个句子留下一棵语法分析树。

      假如我们要将if then else语句加入某一文法G中,我们可以给出无二义性文法如下:

     

               stmt        ->     matched_stmt  

                               |      open_stmt

      matched_stmt ->      if expr then matched_stmt else macthed_stmt

                               |      other

         open_stmt    ->     if expr then stmt

                               |      if expr then matched_stmt else open_stmt

 

      其中加粗的为终结符。

      接下来,我们可以为上面的文法构造语法分析表,这里我们并不会做这一步,而是先来看一下上边语言的一个二义性文法:

 

       S  ->  iEtSS' | a

       S' ->  eS | €

       E  ->  b

 

       其中i、t、e分别代表终结符if、then、else,€代表空串。

       我们先为上边的二义性文法构造语法分析表,这里使用预测分析法的构造方法构造,如下:

      

                     a                b                 e                   i                    t                  $

       S          S->a                                               S->iEtSS'

       S'                                              S'->€                                                    S'->€

                                                       S'->eS                               

       E                            E->b              

 

      现在,当在输入中看到e时,解决选择使用哪个产生式的问题就会显露出此文法的二义性。解决这个二义性问题时,我们选择产生式S'->eS。这个选择就相当于把else和前面的最近的then关联起来。所以我们就可以简单的删掉上表中M[S',e]中的S'->€来消除二义性,此时得到的语法分析表中的每个条目都唯一的指定了一个产生式,或者标明一个语法错误。

      通过使用二义性文法,我们得到了预期的预测分析表,此时我们在回过来看看无二义性文法的预测分析表,虽然没有构建,但我们不难看出无二义性文法的预测分析表要比我们上边得到的复杂,至少构造过程要比我们上边的复杂。由此,我们看到,可以使用精心设计的二义性文法来简化语法分析器的设计。

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用Java语言编写PL/0编译程序的语法分析程序,需要遵循以下步骤: 1. 定义语法规则:根据PL/0语言文法规则定义语法规则,可以使用BNF(巴克斯-诺尔范式)或EBNF(扩展巴克斯-诺尔范式)表示语法规则。 2. 构建语法分析器:使用Java语言编写语法分析器,可以使用自顶向下的递归下降分析法或自底向上的LR分析法。其中,递归下降分析法是最常见的语法分析方法。 3. 分析PL/0程序:将PL/0程序作为输入,使用语法分析器进行分析。如果程序符合语法规则,则输出语法树或抽象语法树,否则报错提示语法错误。 下面是一个简单的使用Java语言编写PL/0编译程序的语法分析程序的示例: ```java import java.util.ArrayList; import java.util.List; public class Parser { private Lexer lexer; private Token currentToken; public Parser(Lexer lexer) { this.lexer = lexer; currentToken = lexer.nextToken(); } public void parse() { program(); } private void program() { block(); match(TokenType.DOT); } private void block() { if (currentToken.getType() == TokenType.CONST) { constDeclaration(); } if (currentToken.getType() == TokenType.VAR) { varDeclaration(); } while (currentToken.getType() == TokenType.PROCEDURE) { procedureDeclaration(); } statement(); } private void constDeclaration() { match(TokenType.CONST); do { match(TokenType.ID); match(TokenType.EQ); match(TokenType.NUM); } while (currentToken.getType() == TokenType.COMMA); match(TokenType.SEMI); } private void varDeclaration() { match(TokenType.VAR); do { match(TokenType.ID); } while (currentToken.getType() == TokenType.COMMA); match(TokenType.SEMI); } private void procedureDeclaration() { match(TokenType.PROCEDURE); match(TokenType.ID); match(TokenType.SEMI); block(); match(TokenType.SEMI); } private void statement() { if (currentToken.getType() == TokenType.ID) { match(TokenType.ID); match(TokenType.ASSIGN); expression(); } else if (currentToken.getType() == TokenType.CALL) { match(TokenType.CALL); match(TokenType.ID); } else if (currentToken.getType() == TokenType.BEGIN) { match(TokenType.BEGIN); statement(); while (currentToken.getType() == TokenType.SEMI) { match(TokenType.SEMI); statement(); } match(TokenType.END); } else if (currentToken.getType() == TokenType.IF) { match(TokenType.IF); condition(); match(TokenType.THEN); statement(); if (currentToken.getType() == TokenType.ELSE) { match(TokenType.ELSE); statement(); } } else if (currentToken.getType() == TokenType.WHILE) { match(TokenType.WHILE); condition(); match(TokenType.DO); statement(); } } private void condition() { expression(); if (currentToken.getType() == TokenType.EQ || currentToken.getType() == TokenType.NE || currentToken.getType() == TokenType.LT || currentToken.getType() == TokenType.LE || currentToken.getType() == TokenType.GT || currentToken.getType() == TokenType.GE) { match(currentToken.getType()); expression(); } } private void expression() { if (currentToken.getType() == TokenType.PLUS || currentToken.getType() == TokenType.MINUS) { match(currentToken.getType()); } term(); while (currentToken.getType() == TokenType.PLUS || currentToken.getType() == TokenType.MINUS) { match(currentToken.getType()); term(); } } private void term() { factor(); while (currentToken.getType() == TokenType.TIMES || currentToken.getType() == TokenType.SLASH) { match(currentToken.getType()); factor(); } } private void factor() { if (currentToken.getType() == TokenType.ID) { match(TokenType.ID); } else if (currentToken.getType() == TokenType.NUM) { match(TokenType.NUM); } else if (currentToken.getType() == TokenType.LPAREN) { match(TokenType.LPAREN); expression(); match(TokenType.RPAREN); } } private void match(TokenType type) { if (currentToken.getType() == type) { currentToken = lexer.nextToken(); } else { throw new RuntimeException("Unexpected token: " + currentToken.getValue()); } } } ``` 在这个示例中,我们定义了PL/0语言的语法规则,并使用自顶向下的递归下降分析法编写了语法分析器,包括了program、block、constDeclaration、varDeclaration、procedureDeclaration、statement、condition、expression和factor等方法。我们使用Lexer类将PL/0程序转换为Token序列,并将其传递给Parser类进行语法分析。最后,我们在main方法中创建Lexer和Parser对象,将PL/0程序传递给Parser的parse方法进行语法分析。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值