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

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); }
    ;

任何人都知道处理这种事情的好方法吗?我是不是错了?

有帮助吗?

解决方案

使用lex / yacc很难处理'传统'shell处理变量替换等问题的方法。他们所做的更像是宏扩展,在扩展变量之后,他们然后重新标记输入,而不扩展其他变量。例如,输入如<!>“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 ':' ....

正如你所看到的,这变得非常复杂。

其他提示

看起来一般不错


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

如果您在询问lex和parse之间的分工,我确信将宏处理和参数替换推入扫描程序并让语法处理WORD s,列表,命令是完全合理的,管道,重定向等等。毕竟,使用代码做一切都是合理的,虽然有点不合时宜,可能会破坏你的练习点。

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

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top