Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/60.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 如何让Ragel解析由(空格*:“空格*)分隔的两个名称?_C_Parsing_Parser Generator_Lexical Analysis_Ragel - Fatal编程技术网

C 如何让Ragel解析由(空格*:“空格*)分隔的两个名称?

C 如何让Ragel解析由(空格*:“空格*)分隔的两个名称?,c,parsing,parser-generator,lexical-analysis,ragel,C,Parsing,Parser Generator,Lexical Analysis,Ragel,我想分析以下内容: name:name 其中名称以alnum开头和结尾,并且可以包含alnum和空格的任意组合。它们也可能是空白的。我的规则是: identifier = alnum (space* alnum)*; name = (identifier | zlen) >sName $pName %fName; sep = space* ":" space*; main := name sep name; 名称可以用冒号分隔,并且可以选择在名称和冒号之间使用空格。我的规

我想分析以下内容:

name:name
其中名称以alnum开头和结尾,并且可以包含alnum和空格的任意组合。它们也可能是空白的。我的规则是:

identifier = alnum (space* alnum)*;
name       = (identifier | zlen) >sName $pName %fName;
sep = space* ":" space*;
main := name sep name;
名称可以用冒号分隔,并且可以选择在名称和冒号之间使用空格。我的规则是:

identifier = alnum (space* alnum)*;
name       = (identifier | zlen) >sName $pName %fName;
sep = space* ":" space*;
main := name sep name;
这不起作用,因为显然
identifier
中的
space*
sep
中的
space*
混淆了解析器。我最终在名称的每个空格中执行动作
fName

如果我将sep更改为:

sep = ":";
那么一切都好了。如何修改这些规则,以便解析器按照我的意图进行操作


此问题的源代码如下:

这类问题有两种基本解决方案

  • 定义操作,以便安全地执行多次
  • 更改语法,使操作只执行一次
  • 在这种情况下,我会选择混合方法。使用操作记录
    名称的开始和结束位置:这些操作可以安全地执行多次,因为它们只记录位置。一旦你确定你已经过了名字,执行一个只执行一次的不同动作

    /* C code */
    char *name_start, *name_end;
    
    /* Ragel code */
    action markNameStart { name_start = p; }
    action markNameEnd { name_end = p; }
    action nameAction {
        /* Clumsy since name is not nul-terminated */
        fputs("Name = ", stdout);
        fwrite(name_start, 1, name_end - name_start, stdout);
        fputc('\n', stdout);
    }
    
    name = space* %markNameStart
           (alnum+ %markNameEnd <: space*)+
           %nameAction ;
    main := name ":" name ;
    
    Ragel机器从左到右扫描,找到
    名称的开头,然后扫描字母数字字符

    Hello world : Goodbye world ↑ 第二个NFA处于以下状态,它假设
    名称
    已经结束(并且该NFA“过早地”执行
    fName
    操作):

    离开操作操作符将一个操作排队,以便嵌入到外出的转换中 通过最终状态对机器进行控制


    对于不一定有助于成功解析的转换,将执行该操作。有关Ragel中的不确定性的更多信息,请参见Ragel指南第4章“控制不确定性”,尽管第4章中的技术在这种特殊情况下对您没有帮助,因为您机器中的操作只能通过未绑定的前瞻来消除歧义,这在有限状态机中是不允许的。

    @Pubby:您给出的表达式与问题中的表达式完全相同。我的问题是,实际上只有一种正确的解析方法,例如,“aa bb:cc dd”。第一个名字必须是“aa bb”,第二个名字必须是“cc dd”。不应该有任何解释的方法,对吗?我已经将name定义为以alnum结尾,它不能包含冒号。在这一点上,我几乎认为这是一个错误。@Ana:只有一种方法可以解释你的代码,而Ragel做的是正确的。这里的问题是,DFA将多次“成功”退出,每次调用
    %
    操作,即使这些退出中只有一个有助于最终解析。你对自动机理论了解多少?如果你不能清楚地说明非确定性自动机和确定性自动机之间的区别(以及为什么这与你的问题相关),Ragel可能看起来有点神秘。 sep = space* ":" space*; ↑ main := name sep name; ↑
    expr % action