Написание лексера для нового языка программирования в Python - PullRequest
0 голосов
/ 08 апреля 2019

Понятия не имею, как / с чего начать. Я должен использовать Python, а точнее, библиотеку ply. Пока что все, что я сделал в создании списка токенов, которые будут частью языка. Этот список приведен ниже:


tokens = (
                                                         # OPERATORS #
    'PLUS' ,        # +
    'MINUS' ,       # -
    'MULTIPLY',     # *
    'DIVIDE',       # /
    'MODULO',       # %


    'NOT',          # ~
    'EQUALS',       # =

                                                         # COMPARATORS #
    'LT',           # <
    'GT',           # >
    'LTE',          # <=
    'GTE',          # >=
    'DOUBLEEQUAL',  # ==
    'NE',           # #


    'AND',          # &
    'OR',           # |
                                                    # CONDITIONS AND LOOPS #    

    'IF',           # if
    'ELSE',         # else
    'ELSEIF',       # elseif
    'WHILE',        # while
    'FOR',          # for
#   'DOWHILE',      # haven't thought about this yet
                                                          # BRACKETS #

    'LPAREN',       # (
    'RPAREN',       # )
    'LBRACE',       # [
    'RBRACE',       # ]
    'BLOCKSTART',   # {
    'BLOCKEND',     # }
                                                        # IDENTIFIERS #

    'INTEGER',      # int
    'DOUBLE',       # dbl
    'STRING',       # str
    'CHAR',         # char

    'SEMICOLON',    # ;
    'DOT',          # .
    'COMMA',        # ,
    'QUOTES',       # '
    'DOUBLEQUOTES', # "
    'COMMENTLINE',  # --

    'RETURN',       # return

)

Мне, очевидно, предстоит долгий путь, поскольку мне также нужно написать синтаксический анализатор и интерпретатор.

У меня есть несколько вопросов:

  1. Как мне использовать библиотеку ply?
  2. Это хорошее начало, и если да, то что мне из этого сделать?
  3. Есть ли какие-либо ресурсы, которые я могу использовать, чтобы помочь мне в этом.

Я пробовал гуглить при написании новых языков программирования, но пока не нашел ничего удовлетворительного

1 Ответ

1 голос
/ 08 апреля 2019

Как использовать библиотеку ply?

Предполагая, что у вас уже установлен Ply, вы должны начать с изучения учебных пособий на официальном веб-сайте Ply .Они хорошо написаны и им легко следовать.

Это хорошее начало, и если да, что мне из этого сделать?

Ply требуется определение токена, чтобы начатьс.Вы уже сделали это.Однако сложности возрастают, когда ваш лексер должен различать, скажем, строку типа «забыть» и зарезервированное ключевое слово, такое как for.Библиотека обеспечивает хорошую поддержку переменных приоритетов для устранения неоднозначности грамматики.Это может быть так же просто, как определить приоритет как кортежи:

precedence = (
 ('left', 'STRING', 'KEYWORD'),
 ('left', 'MULTIPLY', 'DIVIDE')
 )

Однако я рекомендую вам прочитать больше о лексерах и yacc , прежде чем углубляться в более продвинутые функции, такие как выражения и приоритет в Ply.Для начала вы должны создать простой числовой лексер, который успешно анализирует целые числа, операторы и символы в скобках.Я уменьшил определение токена, чтобы соответствовать этой цели.Следующий пример был изменен из официальных руководств.

  • Импорт библиотеки и определение токена :

    import ply.lex as lex #library import
    # List of token names.   This is always required
    tokens = [
                                                         # OPERATORS #
    'PLUS' ,        # +
    'MINUS' ,       # -
    'MULTIPLY',     # *
    'DIVIDE',       # /
    'MODULO',       # %
    
    
    'NOT',          # ~
    'EQUALS',       # =
    
                                                         # COMPARATORS #
    'LT',           # <
    'GT',           # >
    'LTE',          # <=
    'GTE',          # >=
    'DOUBLEEQUAL',  # ==
    'NE',           # !=
    'AND',          # &
    'OR' ,          # |                                                
                                                          # BRACKETS #
    
    'LPAREN',       # (
    'RPAREN',       # )
    'LBRACE',       # [
    'RBRACE',       # ]
    'BLOCKSTART',   # {
    'BLOCKEND',     # }
                                                        # DATA TYPES#
    
    'INTEGER',      # int
    'FLOAT',       # dbl
    
    'COMMENT',  # --
    
    ]
    
  • Определение правил регулярных выражений для простых токенов : Ply использует библиотеку Python re для поиска совпадений регулярных выражений для токенизации.Каждый токен требует определения регулярного выражения.Сначала мы определим определения регулярных выражений для простых токенов.Каждое объявление правила начинается со специального префикса t_, указывающего, что он определяет токен.

    # Regular expression rules for simple tokens
    
    t_PLUS    = r'\+'
    t_MINUS   = r'-'
    t_MULTIPLY   = r'\*'
    t_DIVIDE  = r'/'
    t_MODULO = r'%'
    t_LPAREN  = r'\('
    t_RPAREN  = r'\)'
    t_LBRACE = r'\['
    t_RBRACE = r'\]'
    t_BLOCKSTART = r'\{'
    t_BLOCKEND = r'\}'
    t_NOT = r'\~'
    t_EQUALS = r'\='
    t_GT = r'\>'
    t_LT = r'\<'
    t_LTE = r'\<\='
    t_GTE = r'\>\='
    t_DOUBLEEQUAL = r'\=\='
    t_NE = r'\!\='
    t_AND = r'\&'
    t_OR = r'\|'
    t_COMMENT = r'\#.*'            
    t_ignore  = ' \t' ignore spaces and tabs
    
  • Определение правил регулярных выражений для более сложных токенов подобных данныхтакие типы, как int, float и символы новой строки для отслеживания номеров строк.Вы заметите, что эти определения очень похожи на приведенные выше.

    #Rules for INTEGER and FLOAT tokens
    def t_INTEGER(t):
        r'\d+'
        t.value = int(t.value)    
        return t
    
    def t_FLOAT(t):
        r'(\d*\.\d+)|(\d+\.\d*)'
        t.value = float(t.value)
        return t        
    
    # Define a rule so we can track line numbers
    def t_newline(t):
        r'\n+'
        t.lexer.lineno += len(t.value)
    
  • Добавьте некоторую обработку ошибок для недопустимых символов :

    # Error handling rule
    def t_error(t):
        print("Illegal character '%s'" % t.value[0])
        t.lexer.skip(1)
    
  • Сборка лексера :

    lexer = lex.lex()
    
  • Проверка лексера с некоторыми входными данными, токенизация и печать токенов :

    data = '''
    [25/(3*40) + {300-20} -16.5]
    {(300-250)<(400-500)}
    20 & 30 | 50
    # This is a comment
    '''
    
    # Give the lexer some input
    lexer.input(data)
    
    # Tokenize
    for tok in lexer:
        print(tok)
    

Вы можете добавить этот пример кода в файл скрипта Python, например new_lexer.py, и запустить его как python new_lexer.py.Вы должны получить следующий вывод.Обратите внимание, что входные данные состояли из символов новой строки ('\n'), которые были успешно проигнорированы в выводе.

    #Output
    LexToken(LBRACE,'[',2,1)
    LexToken(INTEGER,25,2,2)
    LexToken(DIVIDE,'/',2,4)
    LexToken(LPAREN,'(',2,5)
    LexToken(INTEGER,3,2,6)
    LexToken(MULTIPLY,'*',2,7)
    LexToken(INTEGER,40,2,8)
    LexToken(RPAREN,')',2,10)
    LexToken(PLUS,'+',2,12)
    LexToken(BLOCKSTART,'{',2,14)
    LexToken(INTEGER,300,2,15)
    LexToken(MINUS,'-',2,18)
    LexToken(INTEGER,20,2,19)
    LexToken(BLOCKEND,'}',2,21)
    LexToken(MINUS,'-',2,23)
    LexToken(INTEGER,16,2,24)
    LexToken(FLOAT,0.5,2,26)
    LexToken(RBRACE,']',2,28)
    LexToken(BLOCKSTART,'{',3,30)
    LexToken(LPAREN,'(',3,31)
    LexToken(INTEGER,300,3,32)
    LexToken(MINUS,'-',3,35)
    LexToken(INTEGER,250,3,36)
    LexToken(RPAREN,')',3,39)
    LexToken(LT,'<',3,40)
    LexToken(LPAREN,'(',3,41)
    LexToken(INTEGER,400,3,42)
    LexToken(MINUS,'-',3,45)
    LexToken(INTEGER,500,3,46)
    LexToken(RPAREN,')',3,49)
    LexToken(BLOCKEND,'}',3,50)
    LexToken(INTEGER,20,4,52)
    LexToken(AND,'&',4,55)
    LexToken(INTEGER,30,4,57)
    LexToken(OR,'|',4,60)
    LexToken(INTEGER,50,4,62)
    LexToken(COMMENT,'# This is a comment',5,65)

Существует множество других функций, которые вы можете использовать.Например, отладку можно включить с помощью lex.lex(debug=True).Официальные руководства содержат более подробную информацию об этих функциях.

Надеюсь, это поможет вам начать работу.Вы можете расширить код, добавив зарезервированные ключевые слова, такие как if, while и идентификацию строки с помощью STRING, идентификацию символа с помощью CHAR.Учебные руководства охватывают реализацию зарезервированных слов, определяя отображение словаря значения ключа следующим образом:

    reserved = {
    'if' : 'IF',
    'then' : 'THEN',
    'else' : 'ELSE',
    'while' : 'WHILE',
    ...
    }

, расширяя список токенов далее, определяя зарезервированный токен type как 'ID' и включая reserved DICT значения: tokens.append('ID') и tokens = tokens + list(reserved.values()).Затем добавьте определение для t_ID, как указано выше.

Есть ли какие-либо ресурсы, которые я могу использовать, чтобы помочь мне в этом.

Есть много ресурсов, доступных для изучения лексеров, парсеров и компиляторов.Вы должны начать с хорошей книги, которая охватывает теорию и реализацию.Есть много книг, которые охватывают эти темы.Мне понравилось это один . Вот другой ресурс, который может помочь.Если вы хотите изучить похожие библиотеки или ресурсы Python, этот SO ответ может помочь.

...