Как изменить порядок разбора правил?

Я разрабатываю язык программирования, и у меня возникают проблемы с операторами условий. Вот код на моем языке:

x = 4 ->
? 2 > 5 <?
    x = 7 -> 
?> ->
[o] <- x ->

Вот конкретная часть грамматики, определяющая условные операторы:

post_condition_evaluation_block : post_condition_evaluation_block_opening_operator compound_statement post_condition_evaluation_block_closing_operator
condition_statement : condition_specification_operator expression post_condition_evaluation_block
                    | condition_specification_operator expression post_condition_evaluation_block condition_extension

На самом деле в грамматике нет ничего плохого, код работает нормально. Проблема в том, что выражение 2 > 5 оценивается после следующего оператора x = 7, поэтому печатается 7 вместо 4 (что неверно, поскольку выражение оценивается как ложное). Я имею дело с этой проблемой, считая блоки условий:

condition_blocks = {0: True}
current_condition_block = 0

И затем, когда дело доходит до утверждения условия:

def p_condition_statement(p):
    """condition_statement : condition_specification_operator expression post_condition_evaluation_block
                           | condition_specification_operator expression post_condition_evaluation_block condition_extension"""
    global current_condition_block
    current_condition_block += 1
    condition_blocks[current_condition_block] = p[2]
    print(condition_blocks)

Он добавляет значение False (p2) выражения к соответствующему блочному индексу в словарь. Проблема в том, что когда я получаю задание:

def p_assignment(p):
    """assignment : identifier assignment_operator expression"""
    if len(p) == 4 and condition_blocks[current_condition_block]:
        if p[2] == '=':
            identifiers[p[1]] = parse_object(p[3])
        elif p[2] == "+=":
            identifiers[p[1]] += parse_object(p[3])
        elif p[2] == "-=":
            identifiers[p[1]] -= parse_object(p[3])
        elif p[2] == "*=":
            identifiers[p[1]] *= parse_object(p[3])
        elif p[2] == "/=":
            identifiers[p[1]] /= parse_object(p[3])
        p[0] = (p[1], p[2], p[3])

Блок, который оценивается, является блоком по умолчанию «вне блока». Правило присваивания анализируется/обрабатывается перед выражением, что не имеет смысла в моей голове, поскольку весь код должен обрабатываться от начала до конца.

Я, очевидно, не эксперт в парсинге / YACC, это моя первая попытка, и я не нахожу абсолютно никакого намека на то, что делать в документах. Я не знаю, как остановить парсер, пропустить парсер, изменить порядок разбора... Возможно, проблема в моей грамматике, но я не вижу, как изменить порядок разбора.


person Ericson Willians    schedule 19.08.2016    source источник


Ответы (1)


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

Единственный практический способ добиться большей гибкости — создать AST во время синтаксического анализа, а затем оценить (или что-то еще) полное выражение, выполнив обход дерева по AST. Затем вы можете пройти все дерево в любом порядке, который вам покажется подходящим.

person rici    schedule 19.08.2016
comment
О, теперь я понял. Я пытался сделать это трудным путем тогда. Большое спасибо за объяснение! - person Ericson Willians; 19.08.2016