Использование ANTLR4 в Python для анализа математических выражений - PullRequest
0 голосов
/ 11 июля 2020

Я новичок в ANTLR4, и я пытаюсь использовать ANTLR для анализа выражений дроби в Python, а затем изменить их на структуру, понятную для Python. Основная причина использования этого выражения вместо регулярного выражения - это рекурсия для вложенных шаблонов.

Структура дроби в моем случае - \\frac{a}{b}, а желаемый формат - (a/b). Подобные проекты уже реализованы, например, Latex2Sympy, но я пытаюсь понять, как это работает.

Парсер может найти совпадение в python. Например, для \frac{1}{2} возвращается (result_ (expr (fraction \frac { 1 } { 2 }))). Результат получается из «дерева», могу ли я извлечь из него части, такие как числа (1 и 2), а затем заменить их в форме (1/2)?

Вот файл грамматики, который я создал:

grammar frac_gram;

options{
    language=Python3;
}

/*
 * Parser Rules
 */

result_    :   expr+ ;
expr       :   fraction;

integer :   INT;
fraction:   FRAC L_BRACE integer R_BRACE L_BRACE integer R_BRACE;

/*
 * Lexer Rules
 */

FRAC:  '\\frac';
L_BRACE: '{';
R_BRACE: '}';
INT :   [0-9]+ ;         // match integers
WS  :   [ \t]+ -> skip ; // toss out whitespace

Код Python:

import sys
from antlr4 import *
from antlr4.InputStream import InputStream
from frac_gram_grammarLexer import frac_gram_grammarLexer
from frac_gram_grammarParser import frac_gram_grammarParser
from frac_gram_grammarVisitor import frac_gram_grammarVisitor

def main(argv):
    input_stream = InputStream(argv)
    lexer = frac_gram_grammarLexer(input_stream)
    token_stream = CommonTokenStream(lexer)
    parser = frac_gram_grammarParser(token_stream)

    tree = parser.result_()

    lisp_tree_str = tree.toStringTree(recog=parser)
    print(lisp_tree_str)

    visitor = frac_gram_grammarVisitor()
    visitor.visit(tree)


if __name__ == '__main__':
    main('\\frac{1}{2}')

1 Ответ

0 голосов
/ 18 июля 2020

После долгих поисков я нашел решение - назвать числитель и знаменатель в файле грамматики, т.е.

fraction:   FRAC L_BRACE upper=integer R_BRACE L_BRACE lower=integer R_BRACE;

Итак, я называю числитель как верхний, а знаменатель как нижний, а затем может быть извлечен в Python после того, как он будет проанализирован анализатором ANTLR по его атрибутам

def convert_fraction(result_of_parser):
   #print(result_of_parser.toStringTree())
   numerator_ = result_of_parser.upper
   denominator_ = result_of_parser.lower
   return sympy.Mul(numerator_ , sympy.Pow(denominator_ , -1, evaluate=False), evaluate=False)
  
...