2

维基百科的插值定义 我只是在学习 flex / bison,我正在用它编写自己的 shell。我正在尝试找出一种进行变量插值的好方法。我最初的方法是对我的主目录或 $myVar 之类的东西进行 flex 扫描,然后使用查找函数将 yyval.string 设置为返回的内容。我的问题是,当文本出现一个标记时,这对我没有帮助:

kbsh:/home/kbrandt% echo ~
/home/kbrandt
kbsh:/home/kbrandt% echo ~/foo
/home/kbrandt /foo
kbsh:/home/kbrandt%

我对变量的 lex 定义:

\$[a-zA-Z/0-9_]+    {
    yylval.string=return_value(&variables, (yytext + sizeof(char)));;
    return(WORD);
}

然后在我的语法中,我有类似的东西:

chdir_command:
    CD WORD { change_dir($2); }
    ;

有人知道处理这种事情的好方法吗?我对这一切都错了吗?

4

2 回答 2

4

“传统”shell 处理变量替换等事情的方式很难用 lex/yacc 处理。他们所做的更像是宏扩展,在扩展变量之后,他们重新标记输入,而不扩展更多变量。例如,像 "xx${$foo}" 这样的输入,其中 'foo' 被定义为 'bar' 而 'bar' 被定义为 '$y' 将扩展为 'xx$y' 这将被视为单个单词(并且 $y 不会被扩展)。

你可以在 flex 中处理这个,但是你需要很多支持代码。您需要使用 flex 的 yy_buffer_state 东西有时将输出重定向到一个缓冲区,然后您将从该缓冲区重新扫描,并仔细使用启动状态来控制变量何时可以扩展和不能扩展。

使用一个非常简单的词法分析器可能更容易,它返回诸如 ALPHA(一个或多个字母字符)、NUMERIC(一个或多个数字)或 WHITESPACE(一个或多个空格或制表符)之类的标记,并让解析器适当地组装它们,并且你最终会得到如下规则:

simple_command: wordlist NEWLINE ;

wordlist: word | wordlist WHITESPACE word ;

word: word_frag
    | word word_frag { $$ = concat_string($1, $2); }
;

word_frag: single_quote_string
         | double_quote_string
         | variable
         | ALPHA
         | NUMERIC
        ...more options...
;

variable: '$' name { $$ = lookup($2); }
        | '$' '{' word '}' { $$ = lookup($3); }
        | '$' '{' word ':' ....

如您所见,这变得非常复杂。

于 2009-09-21T17:43:55.997 回答
1

看起来一般OK


我不确定return_value在做什么,希望它strdup(3)是变量名,因为yytext它只是一个缓冲区。

如果您询问 lex 和 parse 之间的分工,我相信将宏处理和参数替换推送到扫描仪中并让您的语法处理WORDs、列表、命令、管道、重定向等是完全合理的. 毕竟,用代码做所有事情是足够合理的,尽管有点过时并且可能会破坏你的练习点。

我确实认为制作cdchdir终端符号并在语法生产中使用它......不是最好的设计决策。仅仅因为命令是内置的并不意味着它应该作为规则出现。继续解析cdchdir像任何其他命令一样。检查内置语义作为一个动作,而不是一个产品。

毕竟,如果它被重新定义为一个 shell 过程呢?

于 2009-09-19T19:06:47.457 回答