tokenクラスの変更
さて、Ver1の変更ですが、一番簡単そうなtokenクラスから始めます。
tokenの変更は、昨日書いたように
- キーワード mod, div, not, and, or の追加
- 新トークン :=, *, <>, <=, >=, <, >, ), ( の追加
- 上記の追加を token.next()メソッドへ反映させる
という点です。
キーワード、新トークン(新記号)は、 __init__ へ追加してやるだけです。
self.spechar = [':', ',', ';', '.','=', '+', '-', '*', '<', '>', '(', ')']
self.keyword = ['program','const','var','int','integer','bool','boolean',
'begin','end','true','false','mod','div','not','and','or']
token.next()メソッドは、2つの記号の組み合わせ「:=, <>, <=, >=」をトークンとして認識させるように変更を加えます。
記号を認識させる部分
elif self.char in self.spechar: #「記号」の処理
self.token = self.char
self.next_char()
を、以下のように変更します。
elif self.char in self.spechar: #「記号」の処理
self.token = self.char
self.next_char()
if self.token == ':': #代入記号 ':=' の処理
if self.char == '=':
self.token = self.token + self.char
self.next_char()
if self.token == '<': #記号 '<>', '<=' の処理
if self.char in ['>', '=']:
self.token = self.token + self.char
self.next_char()
if self.token == '>': #記号 '>=' の処理
if self.char == '=':
self.token = self.token + self.char
self.next_char()
2つの記号の組み合わせ部分を追加しただけです。
ちょっと長ったらしいですが、トークンクラスの全てを以下に載せます。
#!/usr/bin/python
# coding: utf-8
import sys
class tkn:
def __init__(self, infile, e):
self.infile = infile
self.e = e
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','mod','div','not','and','or']
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になったら
self.e.error(1) #エラーを出す
else:
self.next_char()
self.next_char()
elif self.char == '}': #トークンの頭に}は来ないので
self.e.error(2) #エラーを出す
elif self.char == '#': # #が来たら改行まで読み飛ばす(一行コメント処理)
while self.char != '\n':
if self.char == 'end_of_file':
self.e.error(1)
else:
self.next_char()
elif self.char in self.spechar: #「記号」の処理
self.token = self.char
self.next_char()
if self.token == ':': #代入記号 ':=' の処理
if self.char == '=':
self.token = self.token + self.char
self.next_char()
if self.token == '<': #記号 '<>', '<=' の処理
if self.char in ['>', '=']:
self.token = self.token + self.char
self.next_char()
if self.token == '>': #記号 '>=' の処理
if self.char == '=':
self.token = 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:
self.e.error(3)
#print(self.token)
return self.token
さて、正常に動作してくれるか確認します。
確認用の以下のソースプログラムファイル test.p を作成しました。
program test1;
const
zero = 0;
five = 5;
var
a : integer;
d,e,f : bool;
begin
a := five * (3 + 34);
d := a >= five;
e := zero <> 1;
f := five <= 10;
end.
内容は無いのですが、トークンを認識できるかが目的なので気にしないで下さい。
これを読ませるために、以下のテストファイル test.py を作成します。
#!/usr/bin/python
# coding: utf-8
from err import *
from tkn import *
infile = open('test.p', 'r')
e = err()
token = tkn(infile, e)
token.next_char()
token.next()
while token.token != 'end_of_file':
print(token.token)
token.next()
infile.close()
トークンを読んで、ひとつづつ表示させているだけです。
これを実行させたのが以下になります。
~/PythonProject/PasAvr$ python test.py
program
test1
;
const
zero
=
0
;
five
=
5
;
var
a
:
integer
;
d
,
e
,
f
:
bool
;
begin
a
:=
five
*
(
3
+
34
)
;
d
:=
a
>=
five
;
e
:=
zero
<>
1
;
f
:=
five
<=
10
;
end
.
~/PythonProject/PasAvr$
はい、ちゃんとトークンを認識できています。
今回は無問題ですんなり動いてくれました。
めずらしいことですw