有趣地使用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状态机编译器 。