2

Ragel 是强大的机器,但我在语法中的“可选”元素方面遇到了麻烦。我有简单的数字或字符串。问题在于空格。我不知道如何在“,”和变量之间正确放置可选空格。Enter 将在令牌之间的每个位置。结束行是';' 或进入。我需要使用 $err() 函数来解决错误。

这是我的测试集:好

this , is , a   , test ; and, this,
is,ok

next, trouble
How,produce,good
grammar;
ok

输出:

  • 线(这个,是,一个,测试)

    线(和,这个,是,好的)

    行(下一个,麻烦)

    生产线(如何,生产,好)

    行(语法)

    线(好的)

并且失败(这不是=​​没有',')(',,'没有数字或变量)

this not , working
and,
this,, too

当我使用这个语法时,我在行尾得到单独的字符或错误

 whitespace = [ \t\v\f] ;
 enter      = [\r\n] ;
 string     = (alnum | '_')+ ;
 number     = ('+'|'-')?[0-9]+'.'[0-9]+( [eE] ('+'|'-')? [0-9]+ )? ;
 var        = string | number ;
 koniec     = (';' | enter)  ;
 line       = var whitespace* ( ',' whitespace* var )* whitespace* koniec ;
 main := whitespace* ( line )* ;

这是我的整个代码https://github.com/and09/simple_grammar

4

1 回答 1

1

当你没有完整的语法规范时,很难给出明确的答案,但至少让我们试着让你的例子按照你想要的方式工作,然后你应该能够在需要时纠正它。

因此,您在 Github 中包含一些打印操作的完整示例实际上说明了很多关于状态机中正在发生的事情(在使用 Ragel 时您应该定期检查的另一件事是它可以生成的状态机图你)。在其初始规范(与问题相同)中,它在运行时输出以下内容:

[this]< >,< >[is]

所以进入第三个变量有问题。这是为什么?嗯,那是因为你line只指定了一个( ',' whitespace* var)元素,但是如果你试图通过指定来解决这个问题( ',' whitespace* var)*,它也不会起作用,因为现在你要求你的varis后面紧跟一个重复的逗号,没有任何空格。让我们试试这个(有意删除的操作),将空格移动到重复组中:

line = var whitespace* ( ',' whitespace* var whitespace*)* koniec;

现在你在输出中得到这个:

[this]< >,< >[is]< >,< >[a]< >< >< >,< >[test]< >

这是一个明显的改进。那为什么现在失败了?好吧,那是因为在你koniec的机器想要换成下一个之后line,但为了做到这一点,它需要看到一个var. 但是我们;在输入之后有空格。所以我们需要改变我们对 line 的定义以在开始时启用一些空格,但这也会使空格在main.

line = whitespace* var whitespace* ( ',' whitespace* var whitespace*)* koniec;
main:= line*;

现在我们有这个输出:

[this]< >,< >[is]< >,< >[a]< >< >< >,< >[test]< >
< >[and],< >[this]

哪个更好,但仍然不够好。现在您可以看到它在换行符上阻塞,这对我来说实际上也有点不清楚。你这么说

结束行是';' 或输入

然而你想得到

行(并且,这个,是,好的)

所以让我们假设 enter 开始一个新的line,除非你在行尾有一个逗号。要在语法中指定它,让我们这样做:

line = whitespace* var whitespace* ( ',' (whitespace | enter)* var whitespace*)* koniec;

现在你在输出中得到这个:

[this]< >,< >[is]< >,< >[a]< >< >< >,< >[test]< >
< >[and],< >[this],[is],[ok]

为什么不走得更远?那是因为我们line必须有,var但我们在输入中有一个空行。这也引发了一个只有空格的行的问题,所以让我们line用这样的只有空格的内容来工作:

line       = whitespace* (var whitespace* ( ',' (whitespace | enter)* var whitespace*)*)? koniec;

砰!突然你在输出中拥有了所有你想要的词组。但是你也有一些多余的线条,实际上很容易修复,你只需要将你的pisz_enter动作从koniec这样的线条中移动:

vargroup   = var whitespace* ( ',' %pisz_przecinek (whitespace | enter)* var whitespace*)* %pisz_enter;
line       = whitespace* vargroup? koniec;

而已。我能注意到的另外两件事是:

  • 你希望你number成为这样的人

    number     = (('+'|'-')?[0-9]+'.'[0-9]+( [eE] ('+'|'-')? [0-9]+ )?) >Poczatek_Napisu %pisz_stala ;
    

    正确打印

  • 您实际上需要重做令牌提取才能正常工作,原因是您正在从一些固定数量的块中读取文件,并且您当前正在poczatek_napisu您的操作中存储一些令牌开始指针 ( )。如果令牌在块之间拆分(这很可能发生在任何长于 的文件上sizeof bufor),你就会遇到问题(这不是 FSM 问题,机器可以正常工作,这只是你在行动中所做的) ,但这超出了当前问题的范围。
于 2017-03-11T16:06:02.167 回答