とりあえず、トークン関数の完成だ!
仕上げとして、ソースファイル中のコメント処理を入れてみた。
Pascalは、{と}の間にある文字をコメントとして処理する。なので、その間の文字と{}自身を読み飛ばすようにした。
また、一行コメントも便利なので処理に追加した。
Pascalの進化系Delphiは、c++同様「//」の後の文字を改行までコメントとみなす。Pascalコンパイラを名乗る以上これに準拠しようとも思ったのですが、今勉強中のPythonに敬意を払い「#」から改行までをコメントとした。
スクリプトもちょっとだけ簡単になるし、Python先生も「複雑より簡単の方がいい」とおっしゃっていますし。
あと、error()関数をちょっとだけパワーアップした。
エラー番号を受け取って、エラー内容を表示するという簡単なものだが、無言よりはいいだろう。
書きなおしたのが↓
#!/usr/bin/python
# coding: utf-8
def error(err):
if err == 1:
e = u' 突然ファイルの終端になっています'
elif err == 2:
e = u' }はトークンの始まりには出来ません'
elif err == 3:
e = u' 誤った記号が使用されています'
infile.close()
print('Error' + str(err) + e)
input()
def next_char():
global char
char = infile.read(1)
if not char: #EOFなら(file.read()は、EOFを検出すると空を返す)
char = 'end_of_file'
return char
else:
return char
def next_token():
global char, token
token = ''
while token == '':
if char == '{': #トークンが{の場合
while char != '}': # }まで読み飛ばす(コメント処理)
if char == 'end_of_file': #コメントの途中でEOFになったら
error(1) #エラーを出す
else:
next_char()
next_char()
elif char == '}': #トークンの頭に}は来ないので
error(2) #エラーを出す
elif char == '#': # #が来たら改行まで読み飛ばす(一行コメント処理)
while char != '\n':
if char == 'end_of_file':
error(1)
else:
next_char()
elif char in spechar: #「記号」の処理
token = char
next_char()
elif char in letter: #文字列の処理
token = char
next_char()
while char in (letter + digit):
token = token + char
next_char()
elif char in digit: #数列の処理
token = char
next_char()
while char in digit:
token = token + char
next_char()
elif char in [' ', '\n', '\t', '\r']: #スペース,改行,タブ,リターンは
next_char() #読み飛ばす
elif char == 'end_of_file': #EOFの処理
token = 'end_of_file'
else:
error(3)
return token
digit = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']
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']
spechar = [':', ',', ';', '.','=', '+', '-', '<', '>', '(', ')']
token = ''
infile = open('test.p', 'r')
char = next_char()
while 1:
next_token()
if token == 'end_of_file':
print('EndOfFile')
break
print(token)
infile.close()
●以下のテストファイルを読ませた。
program Pa;
{コメントのテスト
改行してもOKかな?}
var
id1 : integer;
id2 : boolean;
hen : integer;
begin #Python風のコメント
end.
●実行した結果が↓
~/PasAvr$ python gettoken3.py
program
Pa
;
var
id1
:
integer
;
id2
:
boolean
;
hen
:
integer
;
begin
end
.
EndOfFile
~/PasAvr$
ちゃんとコメントを読み飛ばしています。
トークンの取得関数はここでひとまず完成として、次回から先に進みましょう。