Bison 语法不是终端?

Bison 语法不是终端?,bison,yacc,lex,Bison,Yacc,Lex,我目前正在用C、Bison和Flex开发自己的shell 我刚开始学习,但我找不到摆脱语法的方法来让它起作用 我的问题在于argList语法(我想)。arg argList{$1->next=$2;$$=$1;} 用于允许我以后将多个参数传递到列表中 没有它,编译后的解析器就可以按预期工作:它允许我输入MOS令牌并执行该函数,之后允许我继续使用不同(但仅限于一个)参数输入MOS令牌 有了这段语法,解析器允许我输入MOS标记,但只在我按Ctrl+D组合键离开它时才执行该函数。为什么? 谢谢你的回答

我目前正在用C、Bison和Flex开发自己的shell

我刚开始学习,但我找不到摆脱语法的方法来让它起作用

我的问题在于argList语法(我想)。
arg argList{$1->next=$2;$$=$1;}
用于允许我以后将多个参数传递到列表中

没有它,编译后的解析器就可以按预期工作:它允许我输入MOS令牌并执行该函数,之后允许我继续使用不同(但仅限于一个)参数输入MOS令牌

有了这段语法,解析器允许我输入MOS标记,但只在我按Ctrl+D组合键离开它时才执行该函数。为什么?

谢谢你的回答,如果它看起来不好,我很抱歉,但我已经尝试阅读了所有可用的文档,我仍然无法解决这个问题

干杯

野牛代码


commandList
  : command                { $$ = $1; }
  | command commandList  { $1->next = $2; $$ = $1; }
  ;


command
  : MOS argList             { $$ = insert_Mostra( NULL, $2 ); ExecuteCommands($$); }
  ;

argList
  : arg           { $$ = $1; }
  | arg argList   { $1->next = $2; $$ = $1; }
  ;

arg
  : VAR_VALUE { $$ = insert_Args(NULL, $1); }
  ;
有了这段语法,解析器允许我输入MOS标记,但只在我按Ctrl+D组合键离开它时才执行该函数。为什么?

简而言之,因为lex和yacc解析器不适合交互式输入

如果您希望shell是交互式的,而不仅仅是一种批处理脚本语言,那么您需要一种输入机制,它可以从用户那里获取输入行,然后像解析小脚本一样解析它们

如果您使用的是
lex
,这意味着修改扫描仪,使其能够从内存中的缓冲区中获取输入,而不仅仅是从流中获取输入

通过调用
yyparse
,您不能拥有交互式shell,它调用
yylex
,从
stdin
提取字符。如果你这样做了,你会处理各种问题

首先,输入将被行缓冲(在内核中,在TTY级别)
lex
在按Enter键之前不会看到您键入的任何内容

其次,词法分析器和解析器使用“向前看”。为了识别令牌,正则表达式驱动的lexer使用N个字符的前瞻。LALR(1)解析器使用一个前瞻标记。对于用户来说,前瞻性增加了混乱,因为机器一直在等待更多的输入,即使它已经被提供了一个完整的短语

用户想:“为什么机器不计算我输入的完整、语法有效的表达式?”

机器想:“根据我的语法,这个表达式(尽管毫无疑问是有效的)可能只是一个较长表达式的前缀;我需要看看后面有什么,如果有的话!我需要更多的输入,或者一个EOF!”

(为什么lexer需要N个字符的前瞻性?例如,假设我们有一个具有三个固定标记的词汇语法:
aaaaab
a
x
。假设输入是
aaax
。扫描器必须怀疑它可能正在查看
aaaaaab
标记,因此它读取所有
a
字符。)字符,直到它命中
x
。此时,正则表达式自动机意识到
aaaaa b
不可能匹配。而且由于标记不是以
x
开头,它必须查看
a
标记。因此
a
标记返回到解析器。因此,输入位置必须回溯所有way到第二个
a
。换句话说,机器必须在
aax
处查看第一个
a
,以解析令牌:它使用了三个前瞻字符。)


对自由格式输入进行前瞻性分析会将交互最终用户与不可恢复的错误混淆;这是一个非启动的用户界面。

在看到启动下一个命令的MOS之前,它不会对命令执行任何操作。否则,它不知道命令的结束位置。您尝试过了吗?我尝试过了。例如,MOS file1将不会执行任何操作直到我按ctrl+d组合键退出。事情是,
command commandList{$1->next=$2;$$=$1;}
这是阻止它执行的原因,因为它正在等待另一个命令,这就是为什么它只在我结束进程时执行。或者开始键入另一个命令。公平地说,您可以制作一个不错的交互式面向行的解析器,但您必须将
\n
作为标记,并确保在向前看时运行命令是
\n
。然后,只要按enter键,就会运行。