【问题标题】:yacc fails to parse simpe shell grammaryacc 无法解析 simpe shell 语法
【发布时间】:2023-03-09 09:00:01
【问题描述】:

我正在使用 yacc/lex 为 shell 编写一个简单的语法。我希望我的语法能够识别具有以下形式的管道: command1 | command2 | ... | commandn。我能够重新配置一个命令,the simple_command 规则作为下面代码中的开始非终端。但是,当我添加其他规则(simple_command_listpipeline)来解析管道时,事情就不起作用了。为了测试语法,我让 yacc 从以下字符串中读取输入: char *input = "command1 | command2 | command3 | command4\n\0",在主函数中定义。当被要求解析这个字符串时,yacc 只解析第一个命令,打印“解析错误”,然后停止,就像这样:

command "command1"
simple command 
1B
parse error

LEX 代码:

%{ 

#include <string.h> 
#include "y.tab.h" 

%} 

%%


\n      { 
                return NEWLINE; 

        } 

[ \t]   { 
                /* Discard spaces and tabs */ 
        } 

">"     { 
                return GREAT; 
        } 

"<"     { 
                return LESS; 
        } 



“|”    { 
                return PIPE; 
        } 

“&”    { 
                return AMPERSAND; 
        } 


[a-zA-Z][a-zA-Z0-9]*  { 
                /* Assume that file names have only alpha chars */ 
                yylval.str = strdup(yytext); 
                return WORD; 
        } 



.       { 
                /* Invalid character in input */ 
                return BAD_TOKEN;
         }

%%
int yywrap(void) {
return 1;
}

YACC 代码:

%{
#include <string.h>
#include <stdio.h>
int yylex(void);

void yyerror(char *);


%}

%union
{

    char *str;
    int i;

}

%token <i> AMPERSAND GREAT LESS PIPE NEWLINE BAD_TOKEN
%token <str> WORD
%start pipeline
%expect 1


%%

cmd:
    WORD
    {
        printf("command \"%s\"\n", $1);

    }
;

arg:
    WORD
    {

         printf("argument \"%s\"\n", $1);
    }

;

arg_list:
    arg_list arg
    {

        //printf(" argument list: \n");
    }
    | // empty


;

simple_command:
    cmd arg_list
    {

         printf("simple command \n");
    }

;

simple_command_list:
         simple_command_list PIPE simple_command
        {
            printf("1A\n");
        }
        | simple_command
        {
            printf("1B\n");
        }
;

pipeline:
    simple_command_list NEWLINE
    {

    printf("p-A\n");
    }
    | NEWLINE
    {
        printf("p-B\n");
    }
    ;


%%


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


int main(void) {
    // read input from a string
    //YY_BUFFER_STATE *bp;
    struct yy_buffer_state *bp;

    char *input = "command1 | command2 | command3 | command4\n\0";

    //  connect input buffer to specified string
    bp = yy_scan_string(input);

    // read from the buffer
    yy_switch_to_buffer(bp);


    // parse 
    yyparse();

    // delete the buffer
    yy_delete_buffer(bp);

    // delete the string (or not)


    return 0;
}

【问题讨论】:

  • Yacc 完美解析了您的语法,并生成了 C 代码。 你的语法是行不通的。停止转发。

标签: bison yacc lex bnf


【解决方案1】:

您的 lex 源文件包含 unicode 字符,例如 (U-201C 左双引号)和 (U-201D 右双引号),lex 无法将其识别为引号,因此正在寻找包含该 7 字节 utf-8 序列而不是单个字节 | 的输入序列。

用 Ascii " 字符替换那些,它应该可以工作。

如果您使用 bison 的 --debug 选项启用调试,您应该看到它正在获取哪些令牌以及它正在移动和减少哪些规则。在您的情况下,为| 获取BAD_TOKEN...

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多