Рубрики
Без рубрики

Давайте построим простой переводчик с нуля в Python, Pt.10: Tokenizer

Кодировать программу с использованием только рекурсивных списков очень сложно и утомительно. Этот вид тяжелой работы … с меткой переводчика, от Promestatch, Python.

Кодировать программу с использованием только рекурсивных списков очень сложно и утомительно. Такая тяжелая работа должна выполняться компьютерами. Первая задача, которую мы должны преодолеть, заключается в том, что мы каким-то образом превращаем читаемый код программы в структуру, которая может быть легко обработана интерпретатором. Символы, слова и значения должны быть разделены на небольшие значимые структуры, которые называются токенами. В этом посте мы преобразуем это:

a=1;

к этому:

[["name","a"], ["eq",], ["number",1], ["semi",";"]]

[«Имя», «А»] – это токен, как [Тип, значение]. В настоящее время нам не нужно создавать класс токенов ради простоты.

Предупреждение: приведенный ниже код не проверяется на случаи краев. Он был написан, чтобы достичь результата как можно скорее, вместо того, чтобы тратить время на попытку быть идиоматическим. Давай попробуем:

# We need a generator function that yields items of strings or lists:
def gen(xs):
    for x in xs:
        yield x

def tokenize(xs):
    isalpha=lambda x: (x>="a" and x<="z") or (x>="A" and x<="Z") or x=="_"
    reserved="function,set,get,print,return,if,else,for,while,break,continue".split(",")
    symbols={"(":"lparen",")":"rparen","{":"lcurly","}":"rcurly",",":"comma",";":"semi",
             :"equal"}
    g=gen(xs)
    i=next(g)
    tokens=[]
    buf=""
    try:
        while True:
            # Skip whitespace;
            while i in " \r\n\t":
                i=next(g);

            # Token starts with alphas ;
            if isalpha(i):
                # and continues with alphanumeric
                while isalpha(i) or i in "0123456789":
                    buf+=i
                    i=next(g)
                if buf in reserved:
                    tokens.append( [buf,buf] )
                else:
                    tokens.append( ["name",buf] )
                buf=""

            # We found a string;
            if i in "\"'":
                delimiter=i
                i=next(g)
                while i!=delimiter:
                    buf+=i
                    i=next(g)
                # Skip delimiter;
                i=next(g) 
                tokens.append( ["string",buf] )
                buf=""

            # We found a symbol;
            if i in "(){};=,":
                tokens.append( [symbols[i],i] )
                i=next(g)

            # We found a number;
            if i in "+-0123456789":
                while i in "+-0123456789.e":
                    buf+=i
                    i=next(g)
                if "e" in buf or "." in buf:
                    tokens.append( ["number",float(buf)] )
                else:
                    tokens.append( ["number",int(buf)] )
                buf=""

    except StopIteration:
        pass
    return tokens

# test it;
print(tokenize("if (gt(a,b)) return a; else return b;"))

выход:

[['if', 'if'], ['lparen', '('], ['name', 'gt'], ['lparen', '('], ['name', 'a'], ['comma', ','], ['name', 'b'], ['rparen', ')'], ['rparen', ')'], ['return', 'return'], ['name', 'a'], ['semi', ';'], ['else', 'else'], ['return', 'return'], ['name', 'b'], ['semi', ';']]

Это работает: p

В следующем посте мы напишем класс анализатора, который преобразует; » к ‘[“set”, “a”, 1]’

Ссылки: Twitter , Патреон

Оригинал: “https://dev.to/smadev/lets-build-a-simple-interpreter-from-scratch-in-python-pt-10-tokenizer-1d1c”