プログラミングと工作と

PythonとかPascalとかAVRマイコンとか、コンパイラつくったり電子工作なんかを楽しんでいるおっさんの記録

トークンクラスの分離に大成功!

ついにトークンクラスの分離に成功した!
ていうか、「self.」多すぎ。
予約語などの定義もトークンファイルに入れた。これがベストかはわからないけど、メインプログラムがスッキリするのでいいかな、と。

分離した「tkn.py」ファイルを下に示す。

#!/usr/bin/python
# coding: utf-8

import sys

class tkn:             
    
    def __init__(self, infile):
      self.infile = infile
      self.token = ''
      self.char = ''
      self.digit = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
      self.letter = ['A','B','C','D','E','F','G','H','I','J','K','L','M',
                     'N','O','P','Q','R','S','T','U','V','W','X','Y','Z','_',
                     'a','b','c','d','e','f','g','h','i','j','k','l','m',
                     'n','o','p','q','r','s','t','u','v','w','x','y','z']
      self.spechar = [':', ',', ';', '.','=', '+', '-', '<', '>', '(', ')']
      self.keyword = ['program','const','var','int','integer','bool','boolean',
                      'begin','end','true','false']


    def next_char(self):   
        self.char = self.infile.read(1)
        if not self.char:   #EOFなら(file.read()は、EOFを検出すると空を返す)
            self.char = 'end_of_file'
            return self.char
        else:
            sys.stdout.write(self.char)
            return self.char


    def next(self):
        self.token = ''
        while self.token == '':
            if self.char == '{':                    #トークンが{の場合
                while self.char != '}':             # }まで読み飛ばす(コメント処理)
                    if self.char == 'end_of_file':  #コメントの途中でEOFになったら
                        e.error(1)               #エラーを出す
                    else:
                        self.next_char()
                self.next_char()
            elif self.char == '}':  #トークンの頭に}は来ないので
                e.error(2)       #エラーを出す
            elif self.char == '#':  # #が来たら改行まで読み飛ばす(一行コメント処理)
                while self.char != '\n':
                    if self.char == 'end_of_file':
                        e.error(1)
                    else:
                        self.next_char()
            elif self.char in self.spechar:  #「記号」の処理
                self.token = self.char
                self.next_char()
            elif self.char in self.letter:   #文字列の処理
                self.token = self.char
                self.next_char()
                while self.char in (self.letter + self.digit):
                    self.token = self.token + self.char
                    self.next_char()
            elif self.char in self.digit:  #数列の処理
                self.token = self.char
                self.next_char()
                while self.char in self.digit:
                    self.token = self.token + self.char
                    self.next_char()
            elif self.char in [' ', '\n', '\t', '\r']:  #スペース,改行,タブ,リターンは
                self.next_char()                        #読み飛ばす
            elif self.char == 'end_of_file': #EOFの処理
                self.token = 'end_of_file'
            else:
                e.error(3)
        #print(self.token)
        return self.token


メインプログラム側は下の状態です。

#!/usr/bin/python
# coding: utf-8

def ids():
    temp = token.token
    if token.token in token.keyword:
        e.error(4)
    if token.next() not in [',', ':']:
        e.error(5)
    while token.token == ',':
        if token.next() in token.keyword:
            e.error(4)
        temp = temp + ',' + token.token
        token.next()
    return temp


def var_stmts():
    if token.token in token.keyword:
        e.error(4)
    ids()
    if token.token != ':':
        e.error(6)
    if token.next() not in ['int', 'integer', 'bool', 'boolean']:
        e.error(7)
    if token.next() != ';':
        e.error(8)
    if token.next() != 'begin':
        if token.token in token.keyword:
            e.error(9)
    if token.token not in token.keyword:
        var_stmts()
        
        
def const_stmts():
    if token.token in token.keyword:
        e.error(10)
    if token.next() != '=':
        e.error(11)
    x = token.next()
    if x in token.keyword:
        if not x.isdigit():
            if x != '+':
                if x != '-':
                    if x != 'true':
                        if x != 'false':
                            e.error(12)
    if x in ['+','-']:
        token.next()
        if not token.token.isdigit:
            e.error(13)
        x = x + token.token
    if token.next() != ';':
        e.error(8)
    if token.next() in token.keyword:
        if token.token != 'var':
            if token.token != 'begin':
                e.error(14)
    if token.token not in token.keyword:
        const_stmts()


def begin_end_stmt():
    if token.token != 'begin':
        e.error(15)
    if token.next() != 'end':
        e.error(16)
    if token.next() != '.':
        e.error(17)
    token.next()


def consts():
    if token.token != 'const':
        e.error(18)
    if token.next() in token.keyword:
        e.error(10)
    const_stmts()
    

def vars():
    if token.token != 'var':
        e.error(19)
    if token.next() in token.keyword:
        e.error(4)
    var_stmts()


def prog_stmt():
    if token.token != 'program':
        e.error(20)
    token.next()
    if token.token in token.keyword:
        e.error(21)
    if token.next() != ';':
        e.error(8)
    token.next()


def prog():
    if token.token != 'program':
        e.error(20)
    prog_stmt()
    if token.token == 'const':
        consts()
    if token.token == 'var':
        vars()
    if token.token != 'begin':
        e.error(15)
    begin_end_stmt()
    if token.token != 'end_of_file':
        e.error(22)
    print(u'正常終了')


def parser():
    token.next_char()
    if token.next() != 'program':
        e.error(20)
    prog()


from err import *
from tkn import *

infile = open('test.p', 'r')
e = err()
token = tkn(infile)
parser()
infile.close()


で、実行結果が↓

~/PasAvr$ python parser02.py
program test;
const
    yes = true;
    no = false;
    small = 0;
    big = 123456;
var
    id1 : integer;
    id2 : boolean;
    hen : integer;
    x, y, z : int;
begin
end.
正常終了
~/PasAvr$

ちゃんと動いた!