パソコン活用研究5番街(Visual
Basic、Excel(VBA)、BASIC プログラミング研究)
VB.NETで計算機を作る(字句解析)
(準備中)
これはBASICで計算機を作る(字句解析)のVB.NET版です。
基本的に自分の勉強用なのでコードはボロです。異常値のチェックなどは甘々です。
VB.NET版では入力の規則として以下の3つの入力を想定しました。
@ 0〜9の数値
A 演算子として+,-.*,/
B ( ) 括弧
その他のルールとして空白は読みとばす、上記のルールにはずれた文字に出くわしたときは字句解析を中止
ただし、計算機のアルゴリズムの理解を目的にしているので、異常値の入力チェックはあまりしていません。
基本的に正常値が入力されることが前提です。
従って、BASIC版(BASICで計算機を作る(字句解析)では、-0, +0,00というような表記も排除していましたが、
VB.Net版は例えば0が先頭にくる場合のチェックは省略したので、+0は+を無視して0としてトークン化しますが、
-0や000, 001などはそのままトークン化してしまいます。
トークン化の判断は具体的には以下のルールで行っています。
isnum 現在処理中の文字が数値の一部かどうかの状態をあらわすフラグ。
isnum=0 現在処理している文字は数値の一部ではない
isnum=1 現在処理している文字は数値の一部である
変数posをトークンの数を保持するために使っている。
isnum=0 の時 | isnum=1 の時 | |
数値 0〜9 | 数値の始まりとして認識し、isnum=1に変更する | 数値の続きとして認識する |
- | 負の記号として認識し、数値の始まりとしてisnum=1 に変更する |
数値が終了したとみなし、posを一つ加算し、演算子 としてトークン化する。更にposを一つ加算してisnum=0に変更 |
+ * / | 無視 | 数値が終了したとみなし、posを一つ加算し、演算子 としてトークン化する。更にposを一つ加算してisnum=0に変更 |
( | (としてトークン化し、posを1つ加算する。 | 無視 |
) | 無視 | 数値の終了とみなし、posをひとつ加算する。 )としてトークン化する |
上述したように異常値チェックはかなり甘いので、00や001のような表記も許容するし、
isnum=0の時に現れる+ * /は無視するので、1++2のような式は1+2の式として認識する。
以下、VB.NET版特有な個所についての説明。
列挙型
VB.NETの列挙型は以下のように書きます。
Enum クラス名
....
....
End Enum
列挙型に書かれた要素には0から順に数値が自動付与されます。(デフォルト動作)
下記のコードの場合、number=0, add_op=1 が自動付与されています。
列挙型の要素を参照する場合は
列挙型のクラス名.要素
とします。
下記のコードの場合は、
type.number, type.add.op というようになります。
C言語の場合は、列挙型の要素を参照する場合は、要素だけを書けばOKなので
ここに違いがあります。
構造体
構造体は以下のように書きます。
Structure 構造体名
...
...
End Structure
入力された文字列(式)から1文字づつ取り出す。
statement.Chars(i)
で文字列statementからi番目の文字を取り出すことができます。iは0から始まりますので
i=2は3文字目。
Forループから一気に抜け出す場合は、Exit Forを使う(Cだとbreak)
Imports System
Module Program
Enum type
number
add_op
sub_op
mul_op
div_op
lparen
rparen
space
bad
End Enum
Structure token
Dim type As type
Dim str As String
Dim v As Integer
End Structure
Sub Main(args As String())
Dim i, pos, isnum As Integer
Dim r As type
Dim statement As String
Dim token(20) As token
statement = Console.ReadLine()
For i = 0 To statement.Length - 1
Console.WriteLine("{0} : {1}", i, statement.Chars(i))
Next
Console.WriteLine("TOKEN")
pos = 0 : isnum = 0
For i = 0 To statement.Length - 1
r = checktype(statement.Chars(i))
If r = type.space Then GoTo L1 :
If r = type.bad Then Exit For
If isnum = 1 And r = type.number Then token(pos).str = token(pos).str + statement.Chars(i) : token(pos).v = Integer.Parse(token(pos).str) : GoTo L1
If isnum = 1 And r = type.rparen Then pos = pos + 1 : token(pos).str = statement.Chars(i) : token(pos).type = r : GoTo L1
If isnum = 1 And (r = type.add_op Or r = type.sub_op Or r = type.mul_op Or r = type.div_op) Then pos = pos + 1 : token(pos).str = statement.Chars(i) : token(pos).type = r : pos = pos + 1 : isnum = 0 : GoTo L1
If isnum = 0 And r = type.lparen Then token(pos).str = token(pos).str + statement.Chars(i) : token(pos).type = r : pos = pos + 1 : GoTo L1
If isnum = 0 And r = type.number Then token(pos).str = token(pos).str + statement.Chars(i) : token(pos).type = type.number : token(pos).v = Integer.Parse(token(pos).str) : isnum = 1
If isnum = 0 And r = type.sub_op Then token(pos).str = token(pos).str + statement.Chars(i) : token(pos).type = type.number : isnum = 1
L1:
Next
For i = 0 To pos
Console.WriteLine("{0}: {1} : {2}", i, token(i).str, token(i).type)
Next
If r = type.bad Then Console.WriteLine("Wrong expression")
End Sub
Function checktype(ByVal t As String) As Integer
If IsNumeric(t) = True Then Return type.number
If t = "+" Then Return type.add_op
If t = "-" Then Return type.sub_op
If t = "*" Then Return type.mul_op
If t = "/" Then Return type.div_op
If t = "(" Then Return type.lparen
If t = ")" Then Return type.rparen
If t = " " Then Return type.space
Return type.bad
End Function
End Module
TopPage > Visual BasIc&Excel活用研究目次