Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/neo4j/3.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
Compiler construction 如何从正式语法生成句子?_Compiler Construction_Computer Science_Grammar_Parsing - Fatal编程技术网

Compiler construction 如何从正式语法生成句子?

Compiler construction 如何从正式语法生成句子?,compiler-construction,computer-science,grammar,parsing,Compiler Construction,Computer Science,Grammar,Parsing,从语法生成句子的常用方法是什么? 我想要一种与解析器相反的算法。也就是说,给定一个正式的上下文无关语法(比如LL),我想生成一个符合该语法的任意句子。我在这里用句子来表示任何有效的文本体,所以它实际上可以是一个完整的程序(即使它没有任何意义,只要它在语法上是正确的) 语法示例: program : <imports> NEWLINE? <namespace> imports : ("import" <identifier> NEWLINE)* nam

从语法生成句子的常用方法是什么?

我想要一种与解析器相反的算法。也就是说,给定一个正式的上下文无关语法(比如LL),我想生成一个符合该语法的任意句子。我在这里用句子来表示任何有效的文本体,所以它实际上可以是一个完整的程序(即使它没有任何意义,只要它在语法上是正确的)

语法示例:

program   : <imports> NEWLINE? <namespace>
imports   : ("import" <identifier> NEWLINE)* 
namespace : "namespace " <identifier> NEWLINE "{" <classes> "}" 
identifier: (A-Za-z_) (A-Za-z0-9_)*
...

不是答案,但请查看有关语法生成的wikipedia条目:


它描述了一些常用的算法。

我的第一个建议是广度优先搜索。只需建立一个规则图并搜索它们。您将开始从尽可能小的程序开始吐出程序,然后慢慢变大。不过,您可能会发现,对于给定数量的规则,您的语法将以指数形式吐出更多的程序,并且在使用DFS的程序中,您可能无法获得超过30个左右的令牌

深度优先搜索的问题是,第二次使用左递归规则时,搜索将陷入无限循环

另一个大问题是语法正确的程序与语义正确的程序相去甚远。除了最基本的情况外,生成后一种类型可能在所有情况下都是完全不可行的。

虽然这个想法很好(我以前多次考虑过),但现实是,如果没有一些示例数据和/或大量生成器约束/工作限制,这是一项相当大的工作


人们可能会发现手写样本更容易。:)

在我的头顶上:

我会使用一些关于如何处理范围(
(…)
:可能随机选取)选项(
:参见下文[])、重复(“'Poisson分布?)的启发式方法递归地工作(基本上与递归体面解析器相反)。文本(
“…”
)被简单地写入输出,子关键字(`')生成递归

这应该不会太难,除非你想保证某种程度的全面覆盖。即使这样,仅仅生成一堆数据也会有帮助


[*]在处理以下规则时,您需要在少于50%的时间内包含可选项,以防止无限回归

 nonterm:  otherstuff <nonterm>?
非术语:其他东西?
好的,顺其自然

同样地,通过重复,抛出一个强收敛的分布


如果输入语法以BNF形式呈现,则需要首先对其进行解析。最简单的方法是使用一个映射
(名称、字符串)
,然后从最高级别的标记开始(您可能会认为这意味着第一个标记…)

这将为您提供:

(“节目”、“新线?”)

(“进口”,“进口”新行)*)

当你以“程序”开始时,点击“所以你重现……回来时,点击“新线?”,所以掷骰子,写或不写,点击“所以重现……回来时你完成了”


我发现自己怀疑以前有人这样做过。如果你只需要输出,我会在网上搜索。。。也许,尽管大量的解析器生成器将搜索空间搞得一团糟。。。也试试看


顺便说一句,你们当地的大学可能在线订阅了这些期刊,所以你们可以在图书馆免费获得它们。

我不知道有什么“通用”算法可以做到这一点。随机程序生成用于遗传编程,因此您可以寻找基于语法的GP系统,并了解它们如何处理程序生成。我将执行递归规则生成算法,如伪代码:

void GenerateRule(someRule)
{
  foreach (part in someRule.Parts)
  {
    if (part.IsLiteral) OutputLiteral(part);
    if (part.IsIdentifier) Output(GenerateIdentifier(part)));
    if (part.IsRule) GenerateRule(part.Rule);
  }
}
这假设您已经将所有部分读入到某个数据结构中。您还需要处理重复(随机生成重复出现的次数)和可选规则(掷硬币看是否有)



编辑:哦,如果规则有多个选项,您只需选择其中一个选项,并以相同的方式进行处理。因此,如果某个规则是(文字变量),您可以在这两个规则之间随机选择。

您将遇到的问题是,图形的递归性质使得您可以生成无限大的正确语法。您可能需要在语法中设置节点类型的散列,并设置允许自己命中该节点的次数和限制。然后首先深入到你的内心内容。

你的解决方案应该遵循语法的归纳结构。如何为以下每一项生成随机话语

  • 终端符号
  • 非终结符
  • 右侧序列
  • 选择右手边
  • 右侧星形闭合
如果您写下用于表示语法的数据结构,这一切都会更加清楚。相互递归的生成器函数集的结构将非常紧密地反映该数据结构


处理无限递归有点冒险。最简单的方法是生成一系列的话语,并保持深度截止。或者,如果你使用像哈斯克尔这样的懒惰语言,你可以生成所有的话语,并根据你的喜好剥离尽可能多的有限的话语(这是一个比原始问题更棘手的问题,但非常有趣)。

像往常一样,我建议不要重新发明轮子。我为ARM assembler编写了其中一个,但我对此表示遗憾(软件:实践与经验2007年4月):

“回顾过去,本应使用现成的表达式生成器生成随机ARM汇编指令以进行比较。相反,Perl脚本是以增量方式构建的,采用每个ARM指令定义并生成实例。然而,增量内部方法的一个优点是,简单的替换可以检测到删除了简单的bug,bug搜索可以继续递增
void GenerateRule(someRule)
{
  foreach (part in someRule.Parts)
  {
    if (part.IsLiteral) OutputLiteral(part);
    if (part.IsIdentifier) Output(GenerateIdentifier(part)));
    if (part.IsRule) GenerateRule(part.Rule);
  }
}
from nltk import parse_cfg, ChartParser
from random import choice

def produce(grammar, symbol):
    words = []
    productions = grammar.productions(lhs = symbol)
    production = choice(productions)
    for sym in production.rhs():
        if isinstance(sym, str):
            words.append(sym)
        else:
            words.extend(produce(grammar, sym))
    return words

grammar = parse_cfg('''
S -> NP VP
PP -> P NP
NP -> Det N | Det N PP | 'I'
VP -> V NP | VP PP
V -> 'shot' | 'killed' | 'wounded'
Det -> 'an' | 'my' 
N -> 'elephant' | 'pajamas' | 'cat' | 'dog'
P -> 'in' | 'outside'
''')

parser = ChartParser(grammar)

gr = parser.grammar()
print ' '.join(produce(gr, gr.start()))