7

我正在编写一个非常基本的 Web 服务器,它必须支持极其有限的特殊服务器端脚本语言。基本上我需要支持的是“echo”,只有 2 个操作数的加法/减法/乘法(无除法),一个简单的“date()”函数,输出日期和使用“&”运算符连接字符串。

一个例子可能是:

echo "Here is the date: " & date();
echo "9 x 15 = : & 9*15;

我已经完成并创建了生成令牌所需的代码,但我不确定我是否使用了正确的令牌。

我为以下内容创建了令牌:

ECHO - The echo command
WHITESPACE - Any whitespace
STRING - A string inside quotations
DATE - The date() function
CONCAT - the & operator for concatenation
MATH - Any instance of binary operation (5+4, 9*2, 8-2, etc)
TERM - The terminal character (;)

我特别不确定的数学。通常我看到人们专门为整数创建一个标记,然后也为每个运算符创建一个标记,但由于我只想允许二进制操作,我认为将它分组为一个标记是有意义的。如果我要单独做所有事情,我将不得不做一些额外的工作,以确保我永远不会接受“5+4+1”。

所以问题 1 是我在正确的轨道上使用哪些令牌?

我的下一个问题是接下来如何处理这些标记以确保语法正确?我想到的方法基本上是说,“好吧,我知道我有这个令牌,这是一个基于当前令牌允许下一个令牌的列表。下一个令牌在列表中吗?”

基于此,我列出了我的所有标记以及哪些标记可以直接出现在它们之后(为简单起见,不包括空格)。

ECHO        ->      STRING|MATH|DATE
STRING      ->      TERM|CONCAT
MATH        ->      TERM|CONCAT
DATE        ->      TERM|CONCAT
CONCAT      ->      STRING|MATH|DATE

问题是我完全不确定如何最好地实现这一点。真的,我还需要跟踪空格以确保标记之间有空格。但这意味着我必须一次向前看两个令牌,这变得更加令人生畏。我也不确定如何管理“有效的下一个令牌”而不只是 if 块的一些令人作呕的部分。我应该在尝试实际执行脚本之前检查有效的语法,还是应该一次完成所有操作并在遇到意外令牌时抛出错误?在这个简单的例子中,从左到右解析一切都会正常工作,没有真正的优先规则(除了 MATH 的东西,但这就是为什么我将它组合成一个标记的部分原因,即使感觉不对。)即便如此,我也不会'

在我关于编写解析器的研究中,我看到很多关于创建“accept()”和“expect()”函数的参考资料,但我找不到任何关于它们应该做什么或它们应该如何工作的清晰描述.

我想我只是不确定如何实现这一点,然后如何在一天结束时实际拿出一个结果字符串。

我是否朝着正确的方向前进,是否有人知道可以帮助我理解如何最好地实现这样简单的东西的资源?我需要手工完成,不能使用像 ANTLR 这样的工具。

提前感谢您的帮助。

4

2 回答 2

2

您需要做的第一件事是丢弃所有空格(字符串中的空格除外)。这样,当您将令牌添加到令牌列表时,您可以确定该列表仅包含有效令牌。例如,考虑以下语句:

echo "Here is the date: " & date();

我将开始标记化并首先根据空白分离回声(是的,这里需要空白来分离它,但在那之后就没有用了)。然后分词器遇到双引号并继续读取所有内容,直到找到结束双引号同样,我为&date()创建单独的标记。

我的令牌列表现在包含以下令牌:

echo
"这里是日期:"
&
date
()

现在,在解析阶段,我们读取了这些标记。解析器循环遍历令牌列表中的每个令牌。它读取echo并检查它是否有效(基于您对语言的规则/功能)。它前进到下一个标记并查看它是日期字符串还是数学。同样,它检查其余的令牌。如果在任何时候,一个令牌不应该在那里,你可以抛出一个错误,指示语法错误或其他东西。

对于数学语句标记化,仅将括号中包含的表达式与其余操作数和运算符分开组合。例如:9/3 + (7-3+1) 将具有标记 9、/、3、+ 和 (7-3+1)。由于每个令牌都有自己的优先级(您在令牌结构中定义),您可以从最高优先级令牌开始评估到最低令牌优先级。这样你就可以有优先的表达式。如果您仍然有困惑,请告诉我。我会给你写一些示例代码。

于 2012-11-09T16:15:05.983 回答
1

expect是您的解析器为获取下一个令牌所做的事情,如果该令牌不是正确的后续令牌,则会失败。首先,您的解析器expects ECHOWHITESPACE。这些是唯一有效的起始条款。看过“ECHO”后,您的解析器expectsWHITESPACE|STRING|MATH|DATE之一;其他任何事情都是错误。等等。

accept是当您的解析器看到完整的“语句”时 - ECHO,后跟有效的标记序列,然后是TERM。您的解析器现在有足够的信息来处理您的ECHO命令。

哦,手写解析器(尤其是简单的解析器)通常是令人作呕的if块集合(或类似语句的道德等价物switch):) 更进一步的优雅将是某种状态机,更进一步的是像 yacc 或 GOLD Parser Generator 之类的语法生成器(反过来会为您生成丑陋ifswitch, 和状态机)。

编辑以提供更多详细信息。

为了帮助理清职责,创建一个“词法分析器”,其工作是读取输入并生成标记。这涉及确定令牌的外观。一个简单的标记是“回声”这个词。一个不太容易的记号是数学运算;令牌将由一个或多个数字、一个运算符和一个或多个数字组成,中间没有空格。词法分析器会处理跳过空格,以及理解带引号的字符串和构成 date() 函数的字符。词法分析器将返回两件事——读取的标记类型和标记的值(例如,“MATH”和“9*15”)。

有了词法分析器来读取您的输入,解析器会使用标记并确保它们的顺序正确。首先你必须看到ECHO代币。如果不是,则失败并显示错误消息。之后,您必须看到STRINGDATEMATH。如果不是,则失败并显示错误消息。之后,您循环,观察TERMCONCAT后跟另一个STRINGDATEMATH。如果您看到TERM,请打破循环。如果您既没有看到TERM也没有看到CONCAT,则失败并显示错误消息。

您可以在解析时处理 ECHO 命令,因为它是一个简单的语法。每次你找到一个STRINGDATEMATH时,评估它并将它连接到你已经拥有的东西。当你找到TERM时,退出函数并返回构建的字符串。

问题?评论?煎蛋卷?:)

于 2012-11-09T15:52:33.680 回答