この記事に出てくるプログラムは,コンパイラ作りながら学ぶ https://www.ohmsha.co.jp/book/9784274221163/ で紹介されているC言語プログラムや疑似コードをPythonで書き換えたものです.
4.1 文字読み込み
コンパイラはまず,原始プログラムを読み込まなければならない.このときに次のような機能を持つ関数nextCharを作る.
(1) 読み込んだ原始プログラムの中で最後に返した文字の位置を覚えていて
(2) 呼ばれたら,その次の文字を返す.返す文字がなかったらファイルから次の行を読み込みその最初の文字を返す.
import linecache
line_number = 1 #行番号
lineIndex = -1
end = len(open('sample.c').readlines()) #ファイルの行数
def nextChar():
global line_number
global lineIndex
line = linecache.getline('sample.c', int(line_number))
if lineIndex == -1:
if line_number<=end:
lineIndex = 0
else:
print("end of file")
exit(1)
ch = line[lineIndex]
lineIndex+=1
if ch == '\n':
lineIndex = -1
line_number+=1
return ' '
return ch
linecache.getline()で特定の行を文字列として取得する.line_numberが行番号を指定する変数.'\n'を読み込んだ場合lineIndexを-1,lineIndex+=1として,次に関数が呼ばれた際には次の行を読み込む.
4.2 字句読み取り
以下のプログラムは,名前を読み込むためのものです.ここでいう「名前」とは,単語の一文字目が英字,その後に英字または数字のゼロ回以上の繰り返しから成る文字列のことを意味します.state1関数で,一文字目の英字を読み込みます.一文字目が英字でない場合,エラーとなります.次に,state2関数によって,英字or数字の繰り返しから生成される文字列を読み込みます.単語が読み込み終わり,次の単語へと移る際にはstate3関数で,lineindex-=1をします.最終的に変数ansに読み込んだ名前が返される仕組みになっています.
def error():
return "Not Name"
def state3():
global lineIndex
lineIndex-=1
def state1(s):
ch = nextChar()
while ch == ' ':
ch = nextChar() #単語間の空白文字を読み飛ばす
if ch.isalpha():
s+=ch
return state2(s)
else:
return error()
def state2(s):
ch = nextChar()
if ch.isalpha() or ch.isdigit():
s+=ch
return state2(s)
else:
state3()
return s
if __name__ == '__main__':
while True:
ans = state1("")
print(ans)
def error():
return "Error"
def state5():
global lineIndex
lineIndex-=1
def state4(s): #区切り記号
ch = nextChar()
state5()
return s
def state3(s): #数字
ch = nextChar()
if ch.isdigit():
s+=ch
return state3(s)
else:
state5()
return s
def state2(s): #名前
ch = nextChar()
if ch.isalpha() or ch.isdigit():
s+=ch
return state2(s)
else:
state5()
return s
def state1(s):
ch = nextChar()
while ch == ' ':
ch = nextChar() #単語間の空白文字を読み飛ばす
s+=ch
if ch.isalpha(): #名前のとき
return state2(s)
elif ch.isdigit(): #数字のとき
return state3(s)
elif ch == ',' or ch == ';': #区切り記号
return state4(s)
else:
return error()