好的,所以我目前正在编写一个解释器(针对我自己设计的语言),并且在处理 import
时遇到问题。 s。
解释器的工作原理如下:
- 曾经
import <somefile>;
语句被执行,somefile
被加载、解析并执行。 - 这意味着如果一个函数/类在
somefile
中声明,我们的全局函数表中已经创建了一个条目,以便从那时起可以调用它。 - 然后我们继续下一个声明。并执行它。
现在这是问题......
问题 1:
- 假设有一个
doSth
文件中的函数file1
并导入file2
- 如果有
file3
导入file2
,这意味着file1
的 Action 也是可以的。这是不可取的。
问题 2:
- 如果
file1
进口file2
(因为,假设我们需要使用file2
中的函数)和file2
进口file1
,这会导致循环引用(很可能会一直运行到时间结束)
那么,如何解决这些问题呢?有什么想法吗?
我知道这个问题非常专业和复杂,但是如果知道现有解释器/编译器如何处理这个问题,请透露一些信息! ;-)
最佳答案
问题 1
C 和 friend 们所表现出的行为正是您所提示的,这表明无论它有多么令人不快,我们都可以接受:) 但是,许多其他语言也有与您相同的观点。我所知道的所有解决方案都是“申报导出”的某种变体。一般来说,您需要某种机制来指定导出哪些定义(或者不导出哪些定义);如果您需要明确地重新导出导入的定义,那么您将不再遭受默认重新导出的困扰。
但是,您现在遇到了一个稍微不同的问题:
file3:
export cool_definition
file2:
import file3
export bland_definition
/* Use cool_definition */
file1:
import file2 /* Note: only bland_definition is imported */
import file3 /* We want cool_definition */
现在您可能必须确保 cool_definition
在 file1
中直接使用时与 bland_definition
使用时具有相同的含义文件2
。 (取决于您的语言的状态程度,以及您对消除代码重复的关心程度等)
问题 2
假设您同意预处理器导入防护是一个荒谬的黑客,那么您需要记住哪些文件已被导入,并且如果已经或当前正在导入文件,则拒绝导入该文件。这是简单的部分。
使循环导入链发挥作用意味着您需要能够在不知道文件可能依赖的定义的情况下导入文件。例如,如果这些定义是改变程序语法的宏,那么这可能会很棘手。否则,你可以正常收集所有导入的传递闭包;一次处理一个文件以发现定义;然后解析定义(并执行编译所需的任何其他操作)。
Google protobuf 编译器的源代码中有该策略的相当可读的实现(我认为您可以开始浏览 here ,但我已经有一段时间没有查看该代码了。)
关于compiler-construction - 解决循环导入问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23168078/