Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to encapsulate the lex and yacc of PLY in two seperate class

Tags:

python-2.7

ply

I am writing my own parser with PLY. I want to encapsulate the lex and yacc respectively

Here is the code for class Lex:

class Lex:
    tokens = (
        'NAME', 'NUMBER',
    )

    literals = ['=', '+', '-', '*', '/', '(', ')']

    # Tokens

    t_NAME = r'[a-zA-Z_][a-zA-Z0-9_]*'

    ...

the Parser code (which use yacc):

class Parser:

    # Parsing rules
    tokens = Lex.tokens

    def p_statement_assign(self, p):
        'statement : NAME "=" expression'
        self.names[p[1]] = p[3]

   ...

    def run(self):
        print self.tokens
        lex.lex(module=Lex)   # ----what should I do here?-----
        parser = yacc.yacc(module=self)
        parser.parse("1+2")

And I got the following error: unbound method t_NUMBER() must be called with Lex instance as first argument (got LexToken instance instead)

I tried using module=Lex for the lex, just like yacc.yacc(module=self),but it didn't work, anyone could tell the solution.

like image 645
Ryan Avatar asked Jul 08 '16 08:07

Ryan


People also ask

How Lex and YACC communicate with each other?

lex and yacc often work well together for developing compilers. As noted, a program uses the lex-generated scanner by repeatedly calling the function yylex() . This name is convenient because a yacc-generated parser calls its lexical analyzer with this name.

Where is Lex and Yacc used?

You use lex and yacc to produce software that analyzes and interprets input. For example, suppose you want to write a simple desk calculator program. Such a desk calculator is easy to create using lex and yacc, and this tutorial shows how one can be put together.

What is lexing in Python?

A lexer is an analyzer that moves through your code looking at each character, and trying to create tokens out of them. This input. int a =5*5.

Can yacc parse C?

The input to Yacc is a grammar with snippets of C code (called "actions") attached to its rules. Its output is a shift-reduce parser in C that executes the C snippets associated with each rule as soon as the rule is recognized.


1 Answers

This is the first time I've tried building a interpreter. I really don't like PLY for modern Python. It feels weird to use docstrings to house the regular expressions. The PLY samples also seem pretty outdated. But, hey, the first version of PLY was released in 2001 and it is still alive 16 years later, so kudos to the author/community for maintaining it.

That being said, here is how I got some encapsulation to work:

class MyLexer(object):
    tokens = (
        'NUMBER',
        'PLUS', 'MINUS', 'TIMES', 'DIVIDE',
        'LPAREN', 'RPAREN',
    )

    t_PLUS = r'\+'
    t_MINUS = r'-'
    t_TIMES = r'\*'
    t_DIVIDE = r'/'
    t_LPAREN = r'\('
    t_RPAREN = r'\)'

    ...

    def __init__(self):
        # Build the lexer
        self.lexer = lex.lex(module=self)


class MyParser(object):

    tokens = MyLexer.tokens

    ...

    def p_expression_binop(self, t):
        '''
        expression : expression PLUS expression
                   | expression MINUS expression
                   | expression TIMES expression
                   | expression DIVIDE expression
        '''
        left_hand_side = t[1]
        right_hand_side = t[3]
        operator = t[2]
        if operator == '+':
            value = left_hand_side + right_hand_side
        elif operator == '-':
            value = left_hand_side - right_hand_side
        elif operator == '*':
            value = left_hand_side * right_hand_side
        elif operator == '/':
            value = left_hand_side / right_hand_side
        else:
            raise AssertionError('Unknown operator: {}'.format(operator))

        t[0] = value

    ...

    def __init__(self):
        self.lexer = MyLexer()
        self.parser = yacc.yacc(module=self)
like image 54
PaulMest Avatar answered Sep 22 '22 07:09

PaulMest