Контроль отступов при разработке небольшого языка, похожего на Python - PullRequest
5 голосов
/ 30 апреля 2010

Я занимаюсь разработкой небольшого языка, подобного питону, используя flex, byacc (для лексического и синтаксического анализа) и C ++, но у меня есть несколько вопросов, касающихся управления областью действия.

так же, как python, он использует пробелы (или символы табуляции) для отступа, не только это, но я хочу реализовать разрыв индекса, например, если вы введете «break 2» внутри цикла while, который находится внутри другого цикла while, он будет не только разрыв от последнего, но также и от первого цикла (отсюда номер 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, я бы просто использовал символ '}'), мне было интересно, будет ли этот метод лучшим:

Я бы определил глобальную переменную, такую ​​как "int tabIndex" в моем файле yacc, к которой я бы обращался в своем файле lex, используя extern. затем каждый раз, когда я нахожу символ табуляции в моем файле lex, я увеличиваю эту переменную на 1. при синтаксическом анализе моего файла yacc, если я найду ключевое слово "break", я уменьшу его на величину, введенную после него из переменной tabIndex, и когда я достигаю и EOF после компиляции и получаю tabIndex! = 0 я бы вывел ошибку компиляции.

Теперь проблема в том, как лучше узнать, уменьшился ли отступ, следует ли мне читать символы \ b (backspace) из lex, а затем уменьшать переменную tabIndex (когда пользователь не использует break)?

еще один способ добиться этого?

также еще один маленький вопрос, я хочу, чтобы у каждого исполняемого файла была начальная точка в функции start (), если я должен жестко закодировать это в свой файл yacc?

извините за длинный вопрос, любая помощь очень ценится. также, если кто-то может предоставить файл yacc для python, было бы неплохо в качестве руководства (попробовал поискать в Google и не повезло).

Заранее спасибо.

Ответы [ 2 ]

8 голосов
/ 30 апреля 2010

В настоящее время я реализую язык программирования, довольно похожий на этот (включая, как ни странно, многоуровневый разрыв). Мое решение состояло в том, чтобы токенизатор испускал токены отступа и отступа на основе отступа. Например:

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

становится:

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

Это делает обработку токенизатором '\ n' несколько сложной, хотя. Кроме того, я написал токенизатор и парсер с нуля, так что я не уверен, возможно ли это в lex и yacc.

Edit:

Пример полурабочего псевдокода:

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
3 голосов
/ 30 апреля 2010

Очень интересное упражнение. Не можете ли вы использовать ключевое слово end, чтобы проверить, когда заканчивается область?

С другой стороны, я никогда не видел языка, который позволял бы вам разрывать несколько вложенных циклов одновременно. Для этого может быть веская причина ...

...