我正在尝试自学Ruby的Treetop语法生成器.我发现,不仅文档中的"最佳"文档非常稀疏,而且它似乎并不像我希望的那样直观.
在高层次上,我真的很喜欢比现场文档或视频更好的教程,如果有的话.
在较低的层次上,这是一个我根本无法工作的语法:
grammar SimpleTest
rule num
(float / integer)
end
rule float
(
(( '+' / '-')? plain_digits '.' plain_digits) /
(( '+' / '-')? plain_digits ('E' / 'e') plain_digits ) /
(( '+' / '-')? plain_digits '.') /
(( '+' / '-')? '.' plain_digits)
) {
def eval
text_value.to_f
end
}
end
rule integer
(( '+' / '-' )? plain_digits) {
def eval
text_value.to_i
end
}
end
rule plain_digits
[0-9] [0-9]*
end
end
Run Code Online (Sandbox Code Playgroud)
当我加载它并在一个非常简单的测试对象中运行一些断言时,我发现:
assert_equal @parser.parse('3.14').eval,3.14
Run Code Online (Sandbox Code Playgroud)
工作正常,而
assert_equal …Run Code Online (Sandbox Code Playgroud) 我需要为我的一个项目解析一小部分英语,描述为具有(1级)特征结构的无上下文语法(示例),我需要有效地完成它.
现在我正在使用NLTK的解析器,它产生正确的输出,但速度非常慢.对于我的约450个相当模糊的非词典规则和50万个词条的语法,解析简单的句子可能需要2到30秒,这取决于所得到的树的数量.词条对性能几乎没有影响.
另一个问题是在开始时加载(25MB)语法+词典可能需要一分钟.
从我在文献中可以找到的,用于解析这种语法(Earley或CKY)的算法的运行时间应该与语法的大小呈线性关系,并且应该与输入令牌列表的大小相关.我对NLTK的体验表明,歧义是最能伤害表现的,而不是语法的绝对大小.
所以现在我正在寻找一个CFG解析器来取代NLTK.我一直在考虑PLY,但我不知道它是否支持CFG中的特征结构,这在我的情况下是必需的,我看到的例子似乎是在进行大量的过程解析,而不仅仅是指定语法.有人能告诉我一个PLY的例子,它既支持功能结构又使用声明性语法?
对于能够有效地完成我需要的任何其他解析器,我也没问题.Python接口是首选,但不是绝对必要的.
我理解Perl语法是模糊的,它的消歧是非平凡的(有时涉及在编译阶段执行代码).无论如何,Perl是否具有正式语法(尽管模棱两可和/或上下文敏感)?
我发现优先级和关联性是一个很大的障碍,让我理解语法乍看之下对haskell代码的表达.
例如,
blockyPlain :: Monad m => m t -> m t1 -> m (t, t1)
blockyPlain xs ys = xs >>= \x -> ys >>= \y -> return (x, y)
Run Code Online (Sandbox Code Playgroud)
通过实验,我终于明白了,
blockyPlain xs ys = xs >>= (\x -> (ys >>= (\y -> return (x, y))))
Run Code Online (Sandbox Code Playgroud)
代替
blockyPlain xs ys = xs >>= (\x -> ys) >>= (\y -> return (x, y))
Run Code Online (Sandbox Code Playgroud)
其作用如下:
*Main> blockyPlain [1,2,3] [4,5,6]
[(1,4),(1,5),(1,6),(2,4),(2,5),(2,6),(3,4),(3,5),(3,6)]
Run Code Online (Sandbox Code Playgroud)
我可以从ghci获取信息(>> =)作为运算符,(infixl 1 >> =).
但是没有信息 - >因为它不是运营商.
你们中的某些人可以提供一些参考来使这个语法更容易掌握吗?
在龙书中,LL语法定义如下:
语法是LL,当且仅当适用于任何生产时A -> a|b,以下两个条件适用.
FIRST(a)并且FIRST(b)是不相交的.这意味着它们不能同时衍生出来EMPTY
如果b能够获得EMPTY,则a不能推导开头的任何字符串FOLLOW(A),就是FIRST(a)和FOLLOW(A)必须是不相交的.
我知道LL语法不能保持递归,但正式的原因是什么?我猜左递归语法会违反规则2,对吧?例如,我写了以下语法:
S->SA|empty
A->a
Run Code Online (Sandbox Code Playgroud)
由于FIRST(SA) = {a, empty}和FOLLOW(S) ={$, a},然后FIRST(SA)和FOLLOW(S)不脱节,所以这个语法不是LL.但我不知道这是左递归FIRST(SA)而FOLLOW(S)不是不相交,还是有其他原因?换句话说,每个左递归语法都会产生违反LL语法条件2的情况吗?
一周前,我开始了以下项目:一种识别Java代码后缀的语法.
我使用ANTLRJava(Java.g4)的官方语法作为基线并开始添加一些规则.但是,这些新规则还引入了左递归,我也不得不处理.
经过几天的工作,我得到了以下代码.当我开始测试时,我注意到一些不寻常的东西,我仍然无法解释.当给出输入时{ },解析器告诉我no viable alternative at input '<EOF>',但当我在规则的右侧切换终端的顺序时s2,特别是如果我们将右手侧v2_1 | v2_2 | v2_3 ...改为v2_36 | v2_1 | v2_2 ...(终端v2_36移动到第一个位置),顺序{ }被接受.
我的第一个想法是Antlr没有回溯,因为我注意到在输入{ }时,解析器的第一个版本开始遵循规则v2_3,只是报告没有找到任何东西,并且没有尝试考虑其他选项(这是我的想法,但也许不是真的)这样的确v2_36给出了肯定的答案.
但是,经过一些研究,我发现ANTLR实际上是回溯,但只有在其他一切都失败的情况下.至少对于v3.3来说也是如此(在官方ANTLR文件中阅读),但我想这也是如此v4.现在我有点困惑.在这个项目上花了这么多个小时后,如果我不能让它工作,我会觉得非常糟糕.有人可以提供某种提示吗?非常感谢,谢谢.
编辑
管理将问题隔离到
grammar Java;
@parser::members {String ruleName; }
start : compilationUnitSuf EOF;
compilationUnitSuf
: {ruleName = "typeDeclarationSuf"; } s2
;
s2: '{' '}' …Run Code Online (Sandbox Code Playgroud) 许多编程语言允许在列表中的最后一项之后的语法中使用尾随逗号.据说这是为了简化自动代码生成,这是可以理解的.
例如,以下是Java中完全合法的数组初始化(JLS 10.6数组初始化器):
int[] a = { 1, 2, 3, };
Run Code Online (Sandbox Code Playgroud)
我很好奇是否有人知道哪种语言首先允许使用这些尾随逗号.显然C 早在1985年便有它.
此外,如果有人知道现代编程语言的其他语法"特性",我也会非常有兴趣听到这些语言.我读到例如Perl和Python在语法的其他部分允许使用尾随逗号更加自由.
我用if语句尝试了一个很小的代码,尽管它非常简单,但我真的很困惑的是代码
n<-857
while(n!=1){
if(n<=0)
print("please input a positive integer")
else if(n%%2==0)
n<-n/2
print(n)
else
n<-3*n+1
print(n)
}
Run Code Online (Sandbox Code Playgroud)
正如我们在上面看到的,当在R中运行此代码时,会出现错误,但是如果我更改if语句就像这样
if(n<=0)
print("please input a positive integer")
else if(n%%2==0)
n<-n/2
else
n<-3*n+1
Run Code Online (Sandbox Code Playgroud)
没关系,我的问题是我们每次判断只能写一行吗?如果我想在每个评判后做更多的事情,我该怎么做,就像这个案例一样,我想改变n的值,但也想要显示它,我该怎么办?非常感谢你
从语法中生成句子的常用方法是什么?
我想要一种与解析器相反的算法.也就是说,给定一个正式的无上下文语法(比如LL),我想生成一个符合该语法的任意句子.我在这里使用句子来表示任何有效的文本体,因此它实际上可以是一个完整的程序(即使它没有任何意义 - 只要它的语法正确).
示例语法:
program : <imports> NEWLINE? <namespace>
imports : ("import" <identifier> NEWLINE)*
namespace : "namespace " <identifier> NEWLINE "{" <classes> "}"
identifier: (A-Za-z_) (A-Za-z0-9_)*
...
Run Code Online (Sandbox Code Playgroud)
生成的程序示例:
import jkhbhhuob
import aaaaa888_
namespace u8nFGubgykb
{ class ui0op_np { ... }
}
Run Code Online (Sandbox Code Playgroud)