yacc 无法解析 simpe shell 语法
yacc fails to parse simpe shell grammar
我正在使用 yacc/lex 为 shell 编写一个简单的语法。我希望我的语法能够识别具有以下形式的管道:
command1 | command2 | ... | commandn
。我能够在下面的代码中使用 the simple_command
规则作为开始非终端来重新定义单个命令。但是,当我添加额外的规则(simple_command_list
和 pipeline
)来解析管道时,事情不会 work.To 测试语法,我让 yacc 从以下字符串读取输入:
char *input = "command1 | command2 | command3 | command4\n[=18=]"
,定义在main函数中。当要求解析这个字符串时,yacc 只解析第一个命令,打印 "parse error",然后停止,就像这样:
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", );
}
;
arg:
WORD
{
printf("argument \"%s\"\n", );
}
;
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[=13=]";
// 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;
}
您的 lex 源文件包含 Unicode 字符,例如 “
(U-201C 左双引号)和 ”
(U-201D 右双引号),lex 无法将其识别为引号, 因此正在寻找包含该 7 字节 utf-8 序列而不是单个字节的输入序列 |
.
将那些替换为 Ascii "
个字符,它应该可以工作。
如果您使用 bison 的 --debug
选项启用调试,您应该会看到它获得了哪些令牌以及它正在移动和减少哪些规则。在您的情况下,为 |
...
获取 BAD_TOKEN
我正在使用 yacc/lex 为 shell 编写一个简单的语法。我希望我的语法能够识别具有以下形式的管道:
command1 | command2 | ... | commandn
。我能够在下面的代码中使用 the simple_command
规则作为开始非终端来重新定义单个命令。但是,当我添加额外的规则(simple_command_list
和 pipeline
)来解析管道时,事情不会 work.To 测试语法,我让 yacc 从以下字符串读取输入:
char *input = "command1 | command2 | command3 | command4\n[=18=]"
,定义在main函数中。当要求解析这个字符串时,yacc 只解析第一个命令,打印 "parse error",然后停止,就像这样:
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", );
}
;
arg:
WORD
{
printf("argument \"%s\"\n", );
}
;
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[=13=]";
// 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;
}
您的 lex 源文件包含 Unicode 字符,例如 “
(U-201C 左双引号)和 ”
(U-201D 右双引号),lex 无法将其识别为引号, 因此正在寻找包含该 7 字节 utf-8 序列而不是单个字节的输入序列 |
.
将那些替换为 Ascii "
个字符,它应该可以工作。
如果您使用 bison 的 --debug
选项启用调试,您应该会看到它获得了哪些令牌以及它正在移动和减少哪些规则。在您的情况下,为 |
...
BAD_TOKEN