LEX + YACC 在规则的下一行取记号

LEX + YACC taking token in next line for a rule

我正在尝试为我自己的迷你语言构建一个解析器,然后由 YACC 本身将其翻译成 C++。

问题是,YACC 正在读取输入的第一行以及输入的第二行的第一个标记并将其与相应的规则匹配,而它应该只读取输入的第一行中的标记并匹配对应的规则

我的输入文件是:

print "hello"
a = 10
print a

Lex 文件:

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

alpha   [a-zA-Z]
digit   [0-9]

%%
[ \t]                           ;
[ \n]                           { yylineno = yylineno + 1;}
print                           {yylval = strdup(yytext); return PRINT;}
{alpha}({alpha}|{digit})*       {yylval = strdup(yytext); return ID;}
{digit}+                        {yylval = strdup(yytext); return INTEGER;}
\".*\"                          {yylval = strdup(yytext); return STRING;}
"="                             return ASSIGN;
%%

YACC 文件是:

%{
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    extern int yylineno;
    extern FILE *yyin;
    extern FILE *yyout;
    extern char *yytext; 
%}

%token PRINT INPUT INTO ASSIGN INTEGER DECIMAL BOOLVAL CHARACTER

%nonassoc STRING
%nonassoc ID

%%
entry:  entry action    {fprintf(yyout, "\t%s", ); }
    | action            {fprintf(yyout, "\t%s", ); }
    ;

action : print          {$$ = ;}
    | assign            {$$ = ;}
    ;

print : PRINT ID    {
            printf("rule: PRINT ID");
            char* id = strdup();
            strcpy($$, "");
            strcat($$,"cout<<");
            strcat($$,id);
            strcat($$,"<<endl;\n");
        }
    | PRINT STRING  {
            printf("rule: PRINT STRING\n");
            char* str = strdup();
            strcpy($$, "");
            strcat($$,"cout<<");
            strcat($$,str);
            strcat($$,"<<endl;\n");
        }
    | PRINT STRING ID   {
            printf("rule: PRINT STRING ID\n");
            char* str = strdup();
            char* id = strdup();
            strcpy($$, "");
            strcat($$,"cout<<");
            strcat($$,str);
            strcat($$,"<<");
            strcat($$,id);
            strcat($$,"<<endl;\n");
        }
    ;

assign: ID ASSIGN INTEGER {
            char* id = strdup();
            char* val = strdup();
            strcpy($$,"");
            strcat($$,"int ");
            strcat($$,id);
            strcat($$," = ");
            strcat($$,val);
            strcat($$,";\n");
        }
    ;
%%

int main(int argc, char *argv[])
{

    yyin = fopen(argv[1], "r");
    yyout = fopen("out.txt","w");

    if(!yyparse())
        printf("\nParsing complete\n");
    else
        printf("\nParsing failed\n");

    //fclose(yyin);
    fclose(yyout);
    return 0;
}

yyerror(char *s) {
    printf("\n \nLine: %d, Message: %s, Cause: %s\n", yylineno, s, yytext );
}

yywrap()
{
    return 1;
}

预期输出为:

cout<<"hello"<<endl;
int a = 10;
cout<<a<<endl;

但是解析失败,部分输出为:

cout<<"hello"<<a<<endl;

和错误信息:

Line: 2, Message: syntax error, Cause: =

用于减少的规则应该是(以相同的顺序):

PRINT STRING
ID ASSIGN INTEGER
PRINT ID

但是,用于减少的第一个规则是:

PRINT STRING ID

解析失败

ID 在下一行,在 PRINT STRING 之后,但使用的规则仍然是 PRINT STRING ID

我给 STRING 的优先级低于 ID(我想这就是下面代码的意思)

%nonassoc STRING
%nonassoc ID

是这个问题吗?

我无法理解发生了什么。我错过了什么吗?

您的有效打印操作之一是

PRINT STRING ID

您的输入与该操作匹配,但紧跟在该输入之后的是一个 = 符号,解析器无法将其匹配为任何其他操作的开始。

您似乎想要换行符来分隔您的操作。因此,您需要显式创建操作结束标记,更新语法以便您的操作以该标记结束,并让词法分析器在看到换行符时生成标记。