微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

我应该提供什么样的数据结构来处理我的编译器中的作用域?

如何解决我应该提供什么样的数据结构来处理我的编译器中的作用域?

我正在 ubuntu 中开发一个带有 flex 和 bisonc++ 的“玩具”编译器,它将类似 C 的输入语言编译成优化的 C++。 在输入语言中包含一个 main 函数(必须有)并且可以在 main 之外有 optionals 函数,例如:

int myFunc1()
{
  // some functionality
}

int main()
{

}

void myFunf2()
{
  // some functionality
}

在语义分析部分我遇到了麻烦,我不知道如何处理范围,我现在不知道,我应该提供什么样的符号表结构或者我应该为这个问题创建什么样的数据结构。 我的问题有一个复杂的案例(对于语义分析部分):

int Name() // here "Name" is a function name
{
  int Name = 0; // Here Name is a variable name
  return Name // the function returns with the variable
}

int main()
{
  int Name = 5; // Here name is a variable name,it is not the same variable which is in the Name() 
                   function,it is a **different** **variable**
  if ()
  {
    // int Name = 6; <- Name variable cannot be redeclared in this inner if block
    // A variable can be declared once in a function it cannot be redeclared in an if,while,etc. block
  }
}

void Name2()
{
  int Name = 55; // here Name is also a different variable from the others
}

解决方法

作用域符号表的最简单实现是一个能够存储符号和作用域标记的可搜索堆栈。操作很简单:

  • 输入范围:推送范围标记。
  • 声明变量:在验证声明的变量尚未在本地声明后推送声明。
  • 退出范围:弹出堆栈直到范围标记被移除。
  • 查找名称的当前绑定:向下搜索堆栈(即从最新条目开始),直到找到该名称的声明。

如果您以后决定像 C 一样允许局部阴影声明,也可以使用该数据结构。

您在堆栈上的声明对象中存储的内容高度依赖于您的编译器的性质。在最简单的情况下,局部变量只需要与当前堆栈帧中的类型和偏移量相关联。由于作用域也有效地界定了变量的生存期,因此您可以使用作用域标记来保持堆栈帧中的当前偏移量,从而允许您在退出作用域时恢复偏移量。

全局变量需要不同的处理方式,部分原因是函数名可以存储在全局符号表中,部分原因是全局变量的存储分配遵循不同的规则。因此,将全局变量保存在不同的容器中可能会很方便,可能使用哈希表之类的东西,如果在符号堆栈中找不到名称,则搜索此容器。

顺便说一句,我知道建议对姓名进行线性搜索总是会引起人们的注意。事实上,它在执行时间方面并不是最佳的。但是,在项目的这个阶段,更重要的是要专注于让事情顺利进行;您以后可以随时添加更有效的查找程序。 (确保您的符号表提供了一个简单且文档齐全的编程接口。这将使以后修改实现变得更加容易。)无论如何,这真的不是什么大问题。经验表明,绝大多数可见名称在任何时候都是全局的(对应于库函数,其中许多从未被给定的源文本实际使用)。本地名称通常在其声明附近使用。所以花在线性查找上的时间不会成为交易破坏者。如果您担心,请先分析您的编译器,看看它是否显示为重要,然后再花大量精力进行优化。

如果可以在范围内声明全局变量(就像在 C 中一样,使用 extern 关键字),则会出现额外的复杂情况。 (这可能不适用于您的语言;听起来您并没有考虑分布在多个源文件中的程序。但您可能有一天想要添加它。)要正确实现链接,您需要清楚范围名称和外部链接对象的名称。它们是相同的名称,但它们有不同的规则:局部范围的名称仅在声明它的范围内可见,而外部链接对象的名称对链接器可见,因此需要将其添加到另一个符号中未通过名称查找搜索的存储库。此外,可以在多个作用域中声明相同的外部对象。

所有这些都假设您的语言中没有嵌套的函数声明。 C 没有这些,所以这似乎是一个安全的假设。 (将闭包翻译成 C++ 将是一个额外的挑战,我认为这超出了本文的范围。)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。