纠正lex和yacc中的一些简单逻辑错误

时间:2010-12-27 18:55:30

标签: yacc bison lex

我需要帮助解决我在我的例子中遇到的那两个简单的逻辑错误。

以下是详细信息:

输入文件:(input.txt)


姓:James
名字:史密斯
普通文字


输出文件:(output.txt) - [有两个逻辑错误]


姓名是:詹姆斯 名称是:姓氏:史密斯
名称是:普通文本


我期待的是输出(而不是上述行) - [没有逻辑错误]


姓名是:詹姆斯 名字是:史密斯
普通文字


换句话说,我不希望将lastName发送到输出,并且我想匹配普通文本,如果它是在“FirstName:”或“LastName:”之后写的。

这是我的lex文件(example.l):

%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "y.tab.h"

/* prototypes */ 
void yyerror(const char*); 

/* Variables: */
char *tempString;

%}

%START sBody

%%

"FirstName:"                {        BEGIN sBody;        }
"LastName:"                 {        BEGIN sBody;        }

.?                          {        return sNormalText; } 

\n                        /* Ignore end of line */;
[ \t]+                   /* Ignore whitespace */;

<sBody>.+   {
                tempString = (char *)calloc(strlen(yytext)+1, sizeof(char));
                strcpy(tempString, yytext);
                yylval.sValue = tempString;
                return sText;
             }
%%

int main(int argc, char *argv[]) 
{
    if ( argc < 3 )
    {
        printf("Please you need two args: inputFileName and outputFileName");
    }

    else 
    {
        yyin = fopen(argv[1], "r");
        yyout = fopen(argv[2], "w");
        yyparse();
        fclose(yyin);
        fclose(yyout);
    }
    return 0;
} 

这是我的yacc文件:(example.y):

%{
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <ctype.h>
    #include "y.tab.h"

    void yyerror(const char*); 
    int yywrap(); 

    extern FILE *yyout;

    %}

    %union 
    { 
        int iValue;     
        char* sValue;       
    }; 

    %token <sValue> sText
    %token <sValue> sNormalText

    %%

    StartName: /* for empty */
              | sName StartName
          ;

    sName:
         sText  
         { 
                fprintf(yyout, "The Name is: %s\n", $1);
         }
         |
         sNormalText
         {
               fprintf(yyout, "%s\n", $1);
         }
         ;    
    %%

    void yyerror(const char *str) 
    {
        fprintf(stderr,"error: %s\n",str);
    }

    int yywrap()
    {
        return 1;
    } 

如果你能帮助我纠正这些简单的逻辑错误,我将不胜感激。

提前感谢您的帮助和阅读我的帖子。

1 个答案:

答案 0 :(得分:2)

部分麻烦在于您进入州'sody',但您永远不会回到初始状态0。

另一个问题 - 还不是主要问题 - 是你使用右递归语法规则而不是(自然为Yacc)左递归规则:

StartName: /* empty */
      |    sName StartName
      ;

VS

StartName: /* empty */
      |    StartName sName
      ;

BEGIN 0;添加到<sBody> Lex规则可以改善很多事情;剩下的麻烦是你在输出文件中为普通文本中的每个单个字母再输一行'Smith'。您需要查看值如何返回到您的语法。

通过在返回yylval.sValue = yytext;的规则中返回之前添加sNormalText,我得到了'预期'输出。

example.l

%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "y.tab.h"

/* prototypes */
void yyerror(const char*);

/* Variables: */
char *tempString;

%}

%START sBody

%%

"FirstName:"                { puts("FN");      BEGIN sBody;        }
"LastName:"                 { puts("LN");      BEGIN sBody;        }

.?                          { printf("NT: %s\n", yytext); yylval.sValue = yytext; return sNormalText; }

\n                        /* Ignore end of line */;
[ \t]+                   /* Ignore whitespace */;

<sBody>.+   {
                tempString = (char *)calloc(strlen(yytext)+1, sizeof(char));
                strcpy(tempString, yytext);
                yylval.sValue = tempString;
                puts("SB");
                BEGIN 0;
                return sText;
             }

%%

int main(int argc, char *argv[])
{
    if ( argc < 3 )
    {
        printf("Please you need two args: inputFileName and outputFileName");
    }
    else
    {
        yyin = fopen(argv[1], "r");
        if (yyin == 0)
        {
            fprintf(stderr, "failed to open %s for reading\n", argv[1]);
            exit(1);
        }
        yyout = fopen(argv[2], "w");
        if (yyout == 0)
        {
            fprintf(stderr, "failed to open %s for writing\n", argv[2]);
            exit(1);
        }
        yyparse();
        fclose(yyin);
        fclose(yyout);
    }
    return 0;
}

example.y

%{
#include <stdio.h>
#include "y.tab.h"

void yyerror(const char*);
int yywrap();

extern FILE *yyout;

%}

%union
{
    char* sValue;
};

%token <sValue> sText
%token <sValue> sNormalText

%%

StartName: /* for empty */
          | StartName sName
      ;

sName:
     sText
     {
            fprintf(yyout, "The Name is: %s\n", $1);
     }
     |
     sNormalText
     {
           fprintf(yyout, "The Text is: %s\n", $1);
     }
     ;
%%

void yyerror(const char *str)
{
    fprintf(stderr,"error: %s\n",str);
}

int yywrap()
{
    return 1;
}

output.txt的

The Name is: James
The Name is: Smith
The Text is: n
The Text is: o
The Text is: r
The Text is: m
The Text is: a
The Text is: l
The Text is:  
The Text is: t
The Text is: e
The Text is: x
The Text is: t

yywrap()置于词法分析器而不是语法中可能更有意义。我已经在代码中留下了简洁的调试版本 - 它们帮助我了解出现了什么问题。

FN
SB
LN
SB
NT: n
NT: o
NT: r
NT: m
NT: a
NT: l
NT:  
NT: t
NT: e
NT: x
NT: t

您需要使用“.?”规则才能完整返回正常文本。你可能还需要在文件中移动它 - 开始状态是稍微特别的小动物。当我将规则更改为“.+”时,Flex给了我警告:

example.l:25: warning, rule cannot be matched
example.l:27: warning, rule cannot be matched

这些行引用了空白/制表符和sBody规则。在sBody规则移除警告后移动不合格的“.+”,但似乎没有做出所需的操作。玩得开心......