2012-08-08 72 views
1

我正在为一些类似Java的语言做一个简单的解析器(仅用于学习目的)。我无法确定一个语句是否是一个变量声明。这可能是我的词法分析器出现的一个问题(这实在很sl))。如果词法分析器看到一些文本,就会将其标记为标识符,即使该文本是关键字或类型。解析器会告诉他们这些工作。我怎样才能区分一些标识符和一个变量声明?

这在目前的工作,但现在我试图解析变量声明,像这样的一个位置:

int x = 3; 

问题是我不知道如何来确定这是否是一个变量声明。如果我只看了第一令牌,并发现它的“标识符”,并没有告诉我任何事情,因为这行代码还与标识符开头:

System.out.print("hi"); 

而且像这样的语句被处理解析器的另一部分。

我想过的另一个解决方案是检查第一个标记是否是一个类型。例如,我可能有一个类似于如下的方法:

boolean isType(String t) { 
    if(t.equals("int") || 
     t.equals("long") || 
     t.equals("char") || 
     /* et cetera */) 
     return true; 
    else return false; 
} 

这样做的问题是它只允许一组特定的类型。由于我的小语言被编译为Java字节码,因此我需要它将任意类识别为类型。

所以我的问题是:是否有可能确定一个语句是否是变量声明或不知道所有可能的变量类型?

+0

您可能会感到乐观,并且_hope_ Java代码符合样式指南,在这种情况下,类名将全部使用首字母大写。至少这是最简单的情况。 – 2012-08-08 19:33:49

+0

可能吗?是的,还有什么看起来像是一个单词后跟一个空格,后跟另一个单词,后面跟着一个等号? 需要?可能不是,java本身在编译时就知道所有类型,如果你尝试编译一个未知类型的文件,它会给你错误 – 2012-08-08 19:34:16

+1

如果你有两个标识符跟在另一个之后,它还能是什么? – Qnan 2012-08-08 19:36:16

回答

1

大约4年前,我不得不为一堂课做点什么。虽然我不记得所有“官方”做法的细节,但

我会做什么,我会向前看,在未来的符号,以确定它是否是一个变量声明,所以如Benjamin Gruenbaum所述,如果你看到一个合法的标识符(在一行的开头)后面跟着另一个合法的标识符,那么第一个可能是一个变量声明。

+0

我只是试过这个,它工作正常。我无法想象任何两个标识符都不是变量声明的情况(除了函数声明,但在别处处理,所以不应该有任何问题)。谢谢! – Hassan 2012-08-08 19:56:08

+0

@Hassan函数声明后面还有一个参数列表,或者至少是一个'()'后面的参数列表,如果需要将它们与字段或别的区分开来,这只是一个更多的前瞻。 – 2012-08-08 19:59:33

+0

是的,但通常有一些修饰符,如“公共”,“私人”,“静态”等。当然,这是某种Java特定的。 – Hassan 2012-08-08 20:02:37

1

当你读到第一个单词时,你不知道它是否是一个声明,但你不需要。

当你得到下一个分隔符,你知道它是什么。

1

你可能应该阅读关于编译器设计的书,在尝试这个之前可能会先看看lex和yacc代码。或者你可以google writing a compiler

IIRC,它已经有一段时间,首先你打破你的源文件转换成parse tree,然后你走在解析树生成目标代码。当您打破源文件时,您会根据您的关键词标记列表来检查每个标记。

在你的例子中,你的词法分析器会看到'int',并处理它,寻找必须在关键字后面的变量声明(或者在它之前,取决于你的语言定义)。

这使得它看起来很容易,但是有一个原因,为什么大多数人使用像flex或lex这样的工具来创建解析树。

+0

感谢您的回答。我可能不得不做更多的阅读才能更好地理解编译器,但我已经完成了你提到的步骤(解析树和代码生成),现在我可以编译一些简单的代码。我正在为自己的教育做这件事,所以我想避免lex或yacc。 – Hassan 2012-08-08 19:46:20

1

另一种解决方案是让解析器和词法分析器使用符号表进行协作。一旦解析器确定已经声明了一个新的类型名称,它就会将该名称作为类型名称插入到符号表中。词法分析器反过来会查阅符号表以查看新的类似标识符的单词是否是类型名称,并相应地选择正确的标记类型。

但是有一些并发症。

  • 如果语言允许内部范围重新定义类型名称为另一类型的名称,或者作为非类型标识符,符号表必须了解确定范围和解析器必须通知符号表时一个范围结束。
  • 如果语言允许类型名称在某些上下文中成为普通标识符,则解析器必须能够应对这种情况。
  • 如果解析器回溯,则必须记得撤消符号表更改。

它并不像词法分析器忽略上下文那么干净,但作为回报(在某些情况下)它允许解析器避免过度的前瞻和回溯;尽管我认为Java解析器并不一定需要这种帮助。

相关问题