有趣地使用Ragel状态机编译器在int argc,char * argv []上创建行解析函数。
一切始于需要buildargv函数来解析字符串以便随后传输到
int main (int argc, char *argv[]) { body }
好吧,我想,不可能是不可能在任何地方借钱,现在我们找到了……而我却没有找到……

好吧,不是说我根本不会找到它,例如, https://github.com/gcc-mirror/gcc/blob/master/libiberty/argv.c (GPLv2总是很好),我立即承担了这样的义务还没准备好 bash中肯定有这样的功能(GPLv3甚至更好)。 zsh? -去寻找(我发现...-我不想要)。
通常,我没有找到想要的东西,但是我不喜欢自己找到的东西。 好吧,最后,我有权这样做,尽管如此,我自己还是对此过程中的娱乐需求。
我完全不想从字面上用常规的方式写这种情况,我甚至为此感到沮丧。
通常,我们会遇到Ragel状态机编译器。
工具包
该项目可以在这里找到: RAGEL中编写的JOYFUL CMDLINE PARSER
问题陈述
在输入处,我们有任何类型的字符串,任务是从字符串中获取由空格或制表符分隔的参数数组,其中包括:
- 转义字符
\之后的任何字符都必须忽略。 - 在两个双打之间或必须在两个双打之间的任何字符
被视为一个要素 - 如果未封闭
'或" ,则应返回错误
通常,条件不多。 Ragel非常适合此任务。
解释执行
声明一台名为“ buildargv”的计算机,并要求Ragel将其数据放在文件的开头(5.8.1写数据)。
%%{ machine buildargv; write data; }%%
接下来,我们声明一个lineElement机器,该机器依次由两个机器( arg和whitespace )组合(2.5.1 Union)组成。
lineElement = arg >start_arg %end_arg | whitespace; main := blineElements**;
在arg机器的输入和输出处end_arg分别end_arg动作start_arg和end_arg 。
action start_arg { argv_s = p; } action end_arg { nargv = (char**)realloc((*argv), (argc_ + 1)*sizeof(char*)); (*argv) = nargv; (*argv)[argc_] = strndup(argv_s, p - argv_s); argc_++; }
此外,在成功退出arg机器的情况下,任务start_arg将字符的位置保存在输入中,而任务end_arg将新元素添加到argv数组中。
现在,让我们仔细看一下arg 。
arg = '\''> { fcall squote; } | '"'>{ fcall dquote; } | ( '\\'>{fcall skip;} | ^[ \t"'\\] )+;
它由三个机器' , "和(\ | ^[ \t"'\])的联合组成,后者又分别是\和^[ \t"'\] 。
当找到字符'我们称为squote '我们称为squote ,或者如果当前字符为\称为skip ,它将跳过其后的任何字符,并且任何字符都不为0x20 (空格), 0x09 (制表符), ' , "或\被认为是正确的。
仍然需要考虑很小的一部分:
skip := any @{ fret; }; dquote := ( '\\'>{ fcall skip; } | ^[\\] )+ :> ["] @{ fret; } @err(dquote_err); squote := ( '\\'>{ fcall skip; } | ^[\\] )+ :> ['] @{ fret; } @err(squote_err);
使用skip我们已经弄清楚了^['\\]也不应该引起问题。 在这里:>这是Entry-Guarded Concatenation (4.2封装优先级的受保护运算符),其含义是机器( '\\'>{ fcall skip; } | ^['\\] )+当["]返回初始状态。
最后,如果在行尾出现带引号的错误, squote_err dquote_err和squote_err来指示并设置相应的错误代码。
action dquote_err { ret = -1; errsv = BUILDARGV_EDQUOTE; } action squote_err { ret = -1; errsv = BUILDARGV_ESQUOTE; }
代码生成由以下命令执行:
ragel -e -L -F0 -o buildargv.c buildargv.rl
测试行列表可以在test_cmdline.c找到。
结论
问题解决了。
它更快吗? 我对此表示怀疑。 更清楚吗? 只要您是Ragel的专家。
我不假装专制主义,对于Ragel代码的建设性评论,我将不胜感激。
材料清单:
[^ 1]: Adrian Thurston。 Ragel状态机编译器 。