将文本文件附加到 Rascal 中的词典
Append text file to lexicon in Rascal
是否可以将从文本文件中检索到的终端附加到 Rascal 中的词典中?这将在 运行 时间发生,我认为没有明显的方法可以实现这一点。我宁愿将数据与 Rascal 项目分开。例如,如果我从文本文件中读取了国家列表,我该如何将它们添加到词典中(使用 lexical
关键字)?
在 data-dependent 版本的 Rascal 解析器中,这更加容易和快速,但我们还没有发布它。现在我会写一个带有 post-parse 过滤器的通用规则,像这样:
rascal>set[str] lexicon = {"aap", "noot", "mies"};
set[str]: {"noot","mies","aap"}
rascal>lexical Word = [a-z]+;
ok
rascal>syntax LexiconWord = word: Word w;
ok
rascal>LexiconWord word(Word w) { // called when the LexiconWord.word rule is use to build a tree
>>>>>>> if ("<w>" notin lexicon)
>>>>>>> filter; // remove this parse tree
>>>>>>> else fail; // just build the tree
>>>>>>>}
rascal>[Sentence] "hello"
|prompt:///|(0,18,<1,0>,<1,18>): ParseError(|prompt:///|(0,18,<1,0>,<1,18>))
at $root$(|prompt:///|(0,64,<1,0>,<1,64>))
rascal>[Sentence] "aap"
Sentence: (Sentence) `aap`
rascal>
因为 filter
函数移除了 hello
的所有可能派生,解析器最终 returns 在 hello
上出现解析错误。它不会为词典中的 aap
这样做,所以欢呼吧。当然,您可以使用这种过滤进行有趣的复杂推导。人们有时会编写模棱两可的语法并使用像这样的过滤器来使其明确无误。
如果过滤函数是摊销的常量时间,则这种方式的解析和过滤是输入长度的立方 worst-case 时间。如果语法是线性的,那么整个过程当然也是线性的。
一个完全不同的答案是动态更新语法并由此生成解析器。这涉及像这样处理 Rascal 的内部语法表示:
set[str] lexicon = {"aap", "noot", "mies"};
syntax Word = ; // empty definition
typ = #Word;
grammar = typ.definitions;
grammar[sort("Word")] = { prod(sort("Word"), lit(x), {}) | x <- lexicon };
newTyp = type(sort("Word"), grammar);
这个 newType 是一个具体化的语法 + 用于定义词典的类型,现在可以像这样使用:
import ParseTree;
if (type[Word] staticGrammar := newType) {
parse(staticGrammar, "aap");
}
写完这些,还有两件事:
- 我认为这可能会触发未知错误,因为我们没有测试动态解析器生成,并且
- 对于大小合理的词典,这将生成一个非常慢的解析器,因为解析器针对编程语言中的关键字而不是大型词典进行了优化。
是否可以将从文本文件中检索到的终端附加到 Rascal 中的词典中?这将在 运行 时间发生,我认为没有明显的方法可以实现这一点。我宁愿将数据与 Rascal 项目分开。例如,如果我从文本文件中读取了国家列表,我该如何将它们添加到词典中(使用 lexical
关键字)?
在 data-dependent 版本的 Rascal 解析器中,这更加容易和快速,但我们还没有发布它。现在我会写一个带有 post-parse 过滤器的通用规则,像这样:
rascal>set[str] lexicon = {"aap", "noot", "mies"};
set[str]: {"noot","mies","aap"}
rascal>lexical Word = [a-z]+;
ok
rascal>syntax LexiconWord = word: Word w;
ok
rascal>LexiconWord word(Word w) { // called when the LexiconWord.word rule is use to build a tree
>>>>>>> if ("<w>" notin lexicon)
>>>>>>> filter; // remove this parse tree
>>>>>>> else fail; // just build the tree
>>>>>>>}
rascal>[Sentence] "hello"
|prompt:///|(0,18,<1,0>,<1,18>): ParseError(|prompt:///|(0,18,<1,0>,<1,18>))
at $root$(|prompt:///|(0,64,<1,0>,<1,64>))
rascal>[Sentence] "aap"
Sentence: (Sentence) `aap`
rascal>
因为 filter
函数移除了 hello
的所有可能派生,解析器最终 returns 在 hello
上出现解析错误。它不会为词典中的 aap
这样做,所以欢呼吧。当然,您可以使用这种过滤进行有趣的复杂推导。人们有时会编写模棱两可的语法并使用像这样的过滤器来使其明确无误。
如果过滤函数是摊销的常量时间,则这种方式的解析和过滤是输入长度的立方 worst-case 时间。如果语法是线性的,那么整个过程当然也是线性的。
一个完全不同的答案是动态更新语法并由此生成解析器。这涉及像这样处理 Rascal 的内部语法表示:
set[str] lexicon = {"aap", "noot", "mies"};
syntax Word = ; // empty definition
typ = #Word;
grammar = typ.definitions;
grammar[sort("Word")] = { prod(sort("Word"), lit(x), {}) | x <- lexicon };
newTyp = type(sort("Word"), grammar);
这个 newType 是一个具体化的语法 + 用于定义词典的类型,现在可以像这样使用:
import ParseTree;
if (type[Word] staticGrammar := newType) {
parse(staticGrammar, "aap");
}
写完这些,还有两件事:
- 我认为这可能会触发未知错误,因为我们没有测试动态解析器生成,并且
- 对于大小合理的词典,这将生成一个非常慢的解析器,因为解析器针对编程语言中的关键字而不是大型词典进行了优化。