使用下面定义的语法规则,我试图解析一个简单的shell命令,让我们说像cd testFolder
。
这些是我在parser.y中定义的规则:
%union{
char *str;
}
%type <str> WORD
%%
command_list:/*empty*/
|command_list command_line{
printf("myShell > ");
}
;
arg_list:/*empty*/
| arg_list WORD{
printf("Args: %s\n", $2);
free($2);
}
;
cmd_and_args:
WORD arg_list {
printf("CMD: %s\n", $1);
free($1);
}
;
command_line:
cmd_and_args NEWLINE {printf("NULL\n");
}
| NEWLINE {
printf("NULL\n");
}
%%
所以我想要的输出是:
CMD: cd
Args: testFolder
NULL
但我得到的是:
Args: testFolder
CMD: cd
NULL
对于像vim -O test.c test1.c
这样的命令,我得到:
Args: -O
Args: test.c
Args: test1.c
CMD: vim
NULL
args是有序的,但命令最终会到最后。如何以正确的顺序获得它们?
Bison生成自下而上的解析器,这意味着如果您将解析视为树,则会在父节点之前处理节点。 (换句话说,这是一个后序遍历。)
所以行动
cmd_and_args: WORD arg_list { … }
在arg_list
的行动之后执行。
我不明白为什么这会是一个问题,但你可以通过使用Midrule Action或使用单位生产来提取命令字来改变它。
cmd_and_args: WORD { /* print $1*/ arg_list { /* arg_list is now $3 */ }
cmd_and_args: command_word arg_list { … }
command_word: WORD { /* print $1 */ }
注意:语法不代表真正的shell语法,它允许在命令字之前进行赋值(例如.LC_ALL=C sort file.txt
)。
我想我解决了这个,这里是更新的语法:
%union{
char *str;
}
%type <str> WORD
%%
command_list:/*empty*/
|com
mand_list command_line{
printf("myShell > ");
}
;
command_line: simple_command NEWLINE{
printf("NULL\n");
}
| NEWLINE{
printf("NULL\n");
}
;
simple_command: simple_command words
| WORD{
printf("CMD: %s\n", $1);
}
;
words: WORD{
printf("Args: %s\n", $1);
}
%%