我匹配单词来创建简单的词法分析器。 这是我的示例代码和输出 示例代码:
public class
{
public static void main (String args[])
{
System.out.println("Hello");
}
}
输出:
public = identifier
void = identifier
main = identifier
class = identifier
因为你们都可以看到我的输出没有按照输入来安排。 void
和main
在课后出现,但在输出中,class
在结尾处出现。我希望在输入匹配时打印结果。
c#code:
private void button1_Click(object sender, EventArgs e)
{
if (richTextBox1.Text.Contains("public"))
richTextBox2.AppendText("public = identifier\n");
if (richTextBox1.Text.Contains("void"))
richTextBox2.AppendText("void = identifier\n");
if (richTextBox1.Text.Contains("class"))
richTextBox2.AppendText("class = identifier\n");
if (richTextBox1.Text.Contains("main"))
richTextBox2.AppendText("main = identifier\n");
}
答案 0 :(得分:2)
您的代码询问以下问题:
"public"
?如果是,请记下"public = identifier"
。"void"
?如果是,请记下"void = identifier"
。"class"
?如果是,请记下"class = identifier"
。"main"
?如果是,请记下"main = identifier"
。所有这些问题的答案都是肯定的,因为它们按照确切的顺序执行,所以你得到的输出应该不会令人惊讶。注意:public
,void
,class
和main
是关键字,而不是标识符。
在空白处拆分?
因此,您的方法无法帮助您对该输入进行标记。在正确的方向上稍微多一些的东西是input.Split()
- 这将在空白边界处切断输入并为您提供一个字符串数组。不过,那里还有很多空白条目。
input.Split(new char[] { ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries)
稍微好一点,给我们以下输出:public
,class
,{
,public
,static
,{ {1}},void
,main
,(String
,args[])
,{
,System.out.println("Hello");
和}
。
但您会注意到其中一些字符串包含多个标记':}
,(String
和args[])
。如果你有一个带有空格的字符串,它将被分成多个标记。显然,仅仅分割空白是不够的。
<强>标记化强>
此时,您将开始编写一个遍历输入中每个字符的循环,检查它是否为空格或标点字符(例如System.out.println("Hello");
,(
,{ {1}},)
,{
,}
,[
,]
等等。这些字符应被视为前一个标记的结尾,标点字符也应被视为自己的标记。可以跳过空格。
您还必须考虑字符串文字和注释之类的内容:两个双引号之间的任何内容都不应该被标记化,而应被视为单个字符串的一部分&#39;令牌(包括空格)。此外,字符串可以包含生成单个字符的转义序列(例如.
)(双引号不应被视为字符串的结尾,而是作为其内容的一部分)。
在两个正斜杠之后出现的任何内容都应该被忽略(或解析为单个&#39;注释&#39;令牌,如果你想以某种方式处理评论),直到下一个换行符(换行字符/序列在操作中不同)系统)。在遇到;
序列之前,应忽略\"
之后的任何内容。
数字可以选择以减号开头,可以包含一个点(或以点开头),科学记数符部分(/*
),也可以是负数,并且有类型后缀...
换句话说,您正在编写状态机,具有不同的行为,具体取决于您所处的状态:&#39; string&#39;,&#39; comment&#39;,& #39;阻止评论&#39;,&#39;数字文字&#39;等等。
<强>乐星强>
在标记化或单独的步骤(lexing)中为每个标记分配类型很有用。 */
是关键字,e..
是标识符,public
是整数文字,main
是字符串文字,依此类推。这将有助于下一步。
<强>解析强>
您现在可以继续解析:将令牌列表转换为抽象语法树(AST)。此时,您可以检查令牌列表是否实际上是有效代码。你基本上重复了上述步骤,但处于更高的水平。
例如,1234
,"Hello"
和public
是关键字标记,它们是所有访问修饰符。只要遇到其中一个,就会知道必须遵循类,函数,字段或属性定义。如果下一个标记是protected
关键字,则表示错误:private
不是有效的C#构造。但是,如果下一个标记是while
关键字,那么您就知道它是一个类定义并继续解析。
所以你再次获得了一台状态机,但这次你有类别定义&#39;,&#39;功能定义&#39;,&#39;等等。 ;表达&#39;,&#39;二进制表达&#39;一元表达&#39;,&#39;语句&#39;,&#39;赋值语句&#39;等等。< / p>
<强>结论强>
这绝不是完整的,但希望它能让您更好地了解所涉及的所有步骤以及如何处理此问题。还有一些工具可以从语法规范生成解析代码,这可以稍微简化工作(尽管你仍然需要学习如何编写这样的语法)。
您可能还想阅读C#语言规范,特别是有关其语法和词汇结构的部分。该规范可以从Microsofts网站免费下载。
答案 1 :(得分:0)
CodeCaster是对的。你没有走正确的道路。 我不久前作为一个项目制作了一个词法分析器。
我知道,我知道我不应该把东西放在盘子里,但是分析器是针对c ++的,所以你必须改变一些东西。
看看源代码,请尝试了解它至少是如何工作的:C++ Lexical Analyzer
答案 2 :(得分:0)
从严格意义上讲,所描述行为的原因是,在评估代码中,void
的搜索在搜索class
之前出现。然而,对于词法分析来说,总体方法似乎太简单了,因为它只是检查子串。我完全赞同上述评论;根据你想要在大局中实现的目标,可能需要更复杂的方法。