6

我正在使用 flex、byacc(用于词法和解析)和 C++ 开发类似 Python 的小型语言,但我对范围控制有一些疑问。

就像python一样,它使用空格(或制表符)进行缩进,不仅如此,我还想实现索引中断,例如,如果你在另一个while循环内的while循环内键入“break 2”,它不仅会从最后一个,但也从第一个循环开始(因此中断后的数字为 2)等等。

例子:

while 1
    while 1
        break 2
        'hello world'!! #will never reach this. "!!" outputs with a newline
    end
    'hello world again'!! #also will never reach this. again "!!" used for cout
end
#after break 2 it would jump right here

但由于我没有“反”制表符来检查作用域何时结束(例如 C,我只会使用 '}' 字符)我想知道这种方法是否是最好的:

我会在我的 yacc 文件上定义一个全局变量,例如“int tabIndex”,我将使用 extern 在我的 lex 文件中访问它。然后每次我在我的 lex 文件中找到一个制表符时,我都会将该变量增加 1。在解析我的 yacc 文件时,如果我找到一个“break”关键字,我会减少从 tabIndex 变量中键入的数量,当我在编译后到达和 EOF,我得到一个 tabIndex != 0 我会输出编译错误。

现在的问题是,查看缩进是否减少的最佳方法是什么,我应该从 lex 读取 \b (退格)字符,然后减少 tabIndex 变量(当用户不使用 break 时)?

另一种方法来实现这一点?

也只是另一个小问题,我希望每个可执行文件都有一个名为 start() 的函数的起点,我应该将它硬编码到我的 yacc 文件中吗?

很抱歉这个问题很长,非常感谢任何帮助。另外,如果有人可以为 python 提供一个 yacc 文件作为指导(尝试在 Google 上查找但没有运气)。

提前致谢。

4

2 回答 2

8

我目前正在实现一种与此非常相似的编程语言(奇怪的是包括多级中断)。我的解决方案是让标记器根据缩进发出缩进和缩进标记。例如:

while 1: # colons help :)
    print('foo')
    break 1

变成:

["while", "1", ":",
    indent,
    "print", "(", "'foo'", ")",
    "break", "1",
    dedent]

它使标记器对 '\n' 的处理有些复杂。另外,我从头开始编写标记器和解析器,所以我不确定这在 lex 和 yacc 中是否可行。

编辑:

半工作伪代码示例:

level = 0
levels = []
for c = getc():
    if c=='\n':
        emit('\n')
        n = 0
        while (c=getc())==' ':
            n += 1
        if n > level:
            emit(indent)
            push(levels,n)
        while n < level:
            emit(dedent)
            level = pop(levels)
            if level < n:
                error tokenize
        # fall through
    emit(c) #lazy example
于 2010-04-30T03:42:22.197 回答
3

很有趣的练习。您不能使用end关键字检查范围何时结束吗?

另一方面,我从未见过一种语言可以让您一次跳出多个嵌套循环。这可能有一个很好的理由......

于 2010-04-30T03:05:48.640 回答