1

我有一种简单的语言,它由像这样的模式组成

size(50*50)
start(10, 20, -x)
forward(15)
stop

这是海龟绘图语言的一个例子。我需要正确标记它。以上是源代码实例。语句和表达式用换行符分隔。我将我的扫描仪设置为使用换行符等分隔符。我预计next("start")吃掉字符串“start”,然后我发出next("(")吃第一个括号。然而,它似乎做了一些超出我预期的事情。扫描仪是否已经根据分隔符将上述内容分解为标记和/或我是否需要以不同的方式处理?对我来说,第一行的“start”、“(”、“50”、“*”、“50”和“)”将构成单独的标记,这似乎是一个未实现的期望。如何用尽可能少的代码标记上述内容?我目前不需要写分词器,我正在写一个解释器,所以我目前不想花时间在分词上,我只是喜欢 Scanner 在这里和我一起工作。

我的useDelimiter电话如下:

Scanner s ///...
s.useDelimiter(Pattern.compile("[\\s]&&[^\\r\\n]"));

发出第一个next电话会给我整个文件内容。没有上面的调用,它给了我整个第一行。

4

2 回答 2

3

要编写正确的解析器,您需要以正式语法定义您的语言。相信我,你想要正确地做到这一点,否则你会在下游遇到问题。

您可能可以将标记表示为最低级别的正则表达式,但首先您需要清楚您的语法,即词汇结构中标记的组合。您可以将其表示为递归函数(方法),称为产品。每个生产功能都可以使用扫描仪来测试它是否正在查看它想要的令牌。但是扫描仪会消耗输入并且您无法反转。

如果您使用过 Scanner,您会发现以下不合适的地方:

  1. 它总是会根据正则表达式解析一个token,

    1.1 因此,即使您确实获得了可以使用的令牌,您也必须编写更多代码来准确确定它是什么令牌

    1.2 你可能无法将你的语言语法表示为一个大表达式

  2. 你不能重发。前瞻解析器(像您这样的许多语法都需要)需要能够先查看输入流,然后根据需要决定不使用输入并让另一个令牌解析器函数使用它。

我建议您自己编写字符词法分析器,并遍历字符串/字符数组而不是流。然后你可以重新上弦。

否则,请使用现成的词法分析器/解析器框架,如yaccCoco/R

于 2012-10-01T16:33:01.190 回答
2

java.io.StreamTokenizer可能更适合。在递归下降解析器的这个例子中使用它。

附录:之间的主要区别是什么StreamTokenizer Scanner

两者都可以进行解析器所需的词法分析StreamTokenizer重量更轻,但仅限于四个预定义的元令牌。Scanner更加灵活,但使用起来有些麻烦。这是两者的比较以及后者的变化

于 2012-10-01T16:38:19.057 回答