跟我学Lex and Yacc 一

来源:互联网 发布:多彩时时彩做号软件 编辑:程序博客网 时间:2024/04/30 07:16

     最近一段时间在学习作一个c编译器,使用Lex作词法分析器,使用Yacc作语法分析器,其实这两个东东大家都非常熟悉,关于使用它们写出的编译器的文章代码也很多,但我发现一个问题,就是对于语法出错的问题很少谈到,比如int a = 2,这种语法在c语言中来看应该是错误的:应该以分号结尾,等等诸如此类的问题,很少有资料谈到如何处理,本人就在这抛砖引玉,写出自己的一些心得,一起进步。

     我把:http://www.ibm.com/developerworks/cn/linux/l-flexbison.html 中使用 Flex 和 Bison 更好地进行错误处理中的ccalc作为一个例子,讲讲如何作出错处理。

   在parse.y的语法中有这样一段: 

program
    : statement SEMICOLON program
    | statement SEMICOLON
    | statement error SEMICOLON program
      {
      yyerrok;
      }
    ;
statement
    : IDENTIFIER
      {
        var = VarGet($1,
&@1);
      }
      ASSIGN expression
      {
        VarSetValue(var, $4);
      }
    | expression
    ;

上面红色粗体的语法的意思等同于:

$tmp    :      IDENTIFIER                                { var = VarGet($1, &@1);  }

              ;
statement :       $tmp   ASSIGN expression { VarSetValue(var, $3);}

                 ;

注意: tmp只是一个临时的任意值,只是为了说明问题。
  假设现在在defs.txt 中输入这样一句: a = 4  b

在cygwin中执行: ./ccalc.exe defs.txt -debug  > a

//把调试信息写入到了当前文件夹中的文件a中。

在文件a中内容为:

                   === sample program for IBM developerWorks ===    
  ===  ccalc - a sample calculator with variables === 
           *** author: chagen@de.ibm.com ***          
 
debugging activated
reading file 'defs.txt'
       |....+....:....+....:....+....:....+....:....+....:....+....:....+....:
     1 |a = 4 bGetNextChar() => 'a'0x61 at 1
GetNextChar() => ' '0x20 at 2
Token 'a' at 1:1 next at 2
GetNextChar() => '='0x3d at 3
Token ' ' at 2:2 next at 3
Token '=' at 3:3 next at 3
get var a
GetNextChar() => ' '0x20 at 4
GetNextChar() => '4'0x34 at 5
Token ' ' at 3:3 next at 5
GetNextChar() => ' '0x20 at 6
Token '4' at 5:5 next at 6
GetNextChar() => 'b'0x62 at 7
Token ' ' at 6:6 next at 7
Token 'b' at 1:1 next at 0
set var a to 4.000000
...... !.......^-EOF
Error: syntax error, unexpected IDENTIFIER, expecting SEMICOLON
final content of variables
   Name------------------ Value----------
   'a                   ' 4

看到红色粗体的错误吧,当移进4的时候,匹配了关键字VALUE,归约为Expression,当移进b的时候,a = 3就因为匹配上面语法规则中红色粗体的语法规则而归约了,因此在归约后形成了非终结符statement,statement后面应该输入;才应该是正确的语法,但现在因为是输入了b,一个IDENTIFIER 终结符,所以就出错了,这个错误是Bison给出的,我们如何能够知道非终结符statement后面不是一个;呢? 这就设计到一个程序的设计问题,我们可以把每次在lex.l中匹配到的终结符用全局变量保存下来,在归约

statement
    : IDENTIFIER
      {
        var = VarGet($1, &@1);
      }
      ASSIGN expression
      {
        VarSetValue(var, $4);
      }
的时候,判断最后一个匹配的Token验证是否为;如果不是,就弹出自己的提示信息,以实现脚本的错误处理。

 

 

  

 

原创粉丝点击