Как разобрать многострочный код с помощью библиотеки RPLY? - PullRequest
0 голосов
/ 01 февраля 2020

Я работаю над созданием нового языка и использую библиотеку RPLY для целей лексического анализа и анализа. Теперь я застреваю при получении ошибки, когда использую более одной строки в файле кода.

вот мои файлы: -

mylexer.py

from rply import LexerGenerator


class Lexer():
    def __init__(self):
        self.lexer = LexerGenerator()

    def _add_tokens(self):
        # Print
        self.lexer.add('PRINT', r'print')
        # Parenthesis
        self.lexer.add('OPEN_PAREN', r'\(')
        self.lexer.add('CLOSE_PAREN', r'\)')
        # Semi Colon
        self.lexer.add('SEMI_COLON', r'\;')
        # Operators
        self.lexer.add('SUM', r'\+')
        self.lexer.add('SUB', r'\-')
        self.lexer.add('DIV', r'\/')
        self.lexer.add('MUL', r'\*')
        self.lexer.add('MOD', r'\%')
        # Number
        #self.lexer.add('INT', r'^[-+]?\d+$')
        self.lexer.add('NUMBER',r'[-+]?[0-9]*\.?[0-9]+')
        # Ignore spaces
        self.lexer.ignore('\s+')
        #self.lexer.ignore('\n+')
        #self.lexer.ignore('\\*.*?\\*/')

    def get_lexer(self):
        self._add_tokens()
        return self.lexer.build()

myparser.py

from rply import ParserGenerator
from ast import *


class Parser():
    def __init__(self):
        self.pg = ParserGenerator(
            # A list of all token names accepted by the parser.
            ['NUMBER', 'PRINT', 'OPEN_PAREN', 'CLOSE_PAREN',
             'SEMI_COLON', 'SUM', 'SUB','MUL','DIV','MOD']
        )

    def parse(self):

        @self.pg.production('program : PRINT OPEN_PAREN expression CLOSE_PAREN SEMI_COLON')
        def program(p):
            return Print(p[2])

        @self.pg.production('expression : expression SUM expression')
        @self.pg.production('expression : expression SUB expression')
        @self.pg.production('expression : expression MUL expression')
        @self.pg.production('expression : expression DIV expression')
        @self.pg.production('expression : expression MOD expression')
        def expression(p):
            left = p[0]
            right = p[2]
            operator = p[1]
            if operator.gettokentype() == 'SUM':
                return Sum(left, right)
            elif operator.gettokentype() == 'SUB':
                return Sub(left, right)
            elif operator.gettokentype() == 'MUL':
                return Mul(left, right)
            elif operator.gettokentype() == 'DIV':
                return Div(left, right)
            elif operator.gettokentype() == 'MOD':
                return Mod(left, right)

        @self.pg.production('expression : NUMBER')
        def number(p):
            return Number(p[0].value)

        @self.pg.error
        def error_handle(token):
            raise ValueError(token)

    def get_parser(self):
        return self.pg.build()

ast.py

class Number():
    def __init__(self, value):
        self.value = value

    def eval(self):
        try:
            return int(self.value)
        except ValueError:
            return float(self.value)


class BinaryOp():
    def __init__(self, left, right):
        self.left = left
        self.right = right


class Sum(BinaryOp):
    def eval(self):
        return self.left.eval() + self.right.eval()


class Sub(BinaryOp):
    def eval(self):
        return self.left.eval() - self.right.eval()

class Mul(BinaryOp):
    def eval(self):
        return self.left.eval() * self.right.eval()

class Div(BinaryOp):
    def eval(self):
        return self.left.eval() / self.right.eval()

class Mod(BinaryOp):
    def eval(self):
        return self.left.eval() % self.right.eval()



class Print():
    def __init__(self, value):
        self.value = value

    def eval(self):
        print(self.value.eval())

main.py

from mylexer import Lexer
from myparser import Parser

data=""""""
with open('test.vlj', 'r') as file:
    data = file.read()

lexer = Lexer().get_lexer()
tokens = lexer.lex(data)
# print(type(tokens))
# for token in tokens:
#     print(token)

pg = Parser()
pg.parse()
parser = pg.get_parser()
parser.parse(tokens).eval()

test.vlj

print(12.5*2);
print(150+17.5);

Когда я пишу только одну строку в test.vlj, он оценивается, но проблема возникает при использовании более линия. Как мне написать свою продукцию для анализа нескольких строк кода? Также, если возможно, вы можете дать мне несколько ссылок на учебники и документы для изучения RPLY.

1 Ответ

0 голосов
/ 01 февраля 2020
program : PRINT OPEN_PAREN expression CLOSE_PAREN SEMI_COLON

В соответствии с этим программа состоит из одного оператора печати, поэтому print(12.5*2); print(150+17.5); просто не соответствует грамматике.

Я бы предложил переименовать указанное выше правило в statement и затем есть правило program, которое может соответствовать одному или нескольким операторам. Производство для этого будет program : program statement и program : statement.

...