编写自己的Shell解释器-4[转]
根据这个思路,我们来看对应的 lex 规则。
%%
"\"" {BEGIN QUOTE;} <QUOTE>[^\n"]+ {add_arg(yytext);} <QUOTE>"\"" {BEGIN 0;} <QUOTE>\n {BEGIN 0; do_list_cmd(); reset_args();} ";" {add_simple_arg(yytext);} ">" {add_simple_arg(yytext);} "<" {add_simple_arg(yytext);} "|" {add_simple_arg(yytext);} [^ \t\n|<>;"]+ {add_arg(yytext);} \n {do_list_cmd(); reset_args();} . ; %%
|
我们对这些规则逐条解释:
1-4这4条规则,目的是为了在命令行中支持引号,它们用到了 lex 规则的状态特性。
1、"\"" {BEGIN QUOTE;}
2、<QUOTE>[^\n"]+ {add_arg(yytext);}
3、<QUOTE>"\"" {BEGIN 0;}
4、<QUOTE>\n {BEGIN 0; do_list_cmd(); reset_args();}
1、 如果扫描到引号( “),那么进入 QUOTE 状态。在这个状态下,即使扫描到空白字符或“;”、“>”、“<”、“|”,也要当作普通的字符。
2、 如果处于 QUOTE状态,扫描到除引号和回车以外的字符,那么调用 add_arg()函数,把整个字符串加入到参数数组中。
3、 如果处于QUOTE状态,扫描到引号,那么表示匹配了前面的引号,于是恢复到默认状态。
4、 如果处于QUOTE状态,扫描到回车,那么结束了本次扫描,恢复到默认状态,并执行 do_list_cmd(),来执行对列表命令的处理。
以下几条规则,是在处于默认状态的情况下的处理。
5、";" {add_simple_arg(yytext);}
6、">" {add_simple_arg(yytext);}
7、"<" {add_simple_arg(yytext);}
8、"|" {add_simple_arg(yytext);}
9、[^ \t\n|<>;"]+ {add_arg(yytext);}
10、\n {do_list_cmd(); reset_args();}
5、 如果遇到分号(;),因为这是一个列表命令结束的操作符,所以作为一个单独的参数,执行 add_simple_arg(),将它加入参数数组。
6、 如果遇到 >,因为这是一个简单命令结束的操作符,所以作为一个单独的参数,执行 add_simple_arg(),将它加入参数数组。
7、 如果遇到 <,因为这是一个简单命令结束的操作符,所以作为一个单独的参数,执行 add_simple_arg(),将它加入参数数组。
8、 如果遇到管道符号(|),因为这是一个管道命令结束的操作符,所以作为一个单独的参数,执行 add_simple_arg(),将它加入参数数组。
9、 对于不是制表符(tab)、换行符(’\n’)、| 、<、>和分号(;)以外的字符序列,作为一个普通的参数,加入参数数组。
10、 如果遇到换行符,那么结束本次扫描,执行 do_list_cmd(),来执行对列表命令的处理。
11、 对于任意其它字符,忽略
通过 lex 的“规则”把用户输入的命令行分解成一个个的参数之后,都要执行 do_list_cmd() 来执行对列表命令的处理。