2012-01-10 5 views
0

現在、8つのキーワード(大文字と小文字を区別しない)と4つの算術演算子を持つ基本インタプリタを作成する課題があります。複数のarraylistsまたは文字列トークン付き配列を使用してJavaでインタプリタを書く

# (signals start of a comment line) 
LET 
INTEGER 
STRING 
PRINT 
END 

とにかく私は現在解析するテキストの行をトークン化しようとしている:この言語でのプログラムは、(実際にはBASICの構文に似ています)、このようになります。私はすでに、すべての行のテキストをArrayListに解析し、文字列をトークン化しました。私の現在の問題は、StringTokenizerがすべての文字列を事前にトークン化していることです(私は区切り文字として空白を使用しています)。私の必要とするのは、キーワードの検索です。これは常にコード行の最初の部分です特定の問題がそれを望ましくないものにしてしまいます。私はString.split()を使用することも多くの助けになるとは思わない。

インタプリタに最初のトークンを見つけさせ、そこからHashMapを介して適切なクラスに移動することでした(私の以前のインタプリタのswitch文の使用に関する私の以前の質問: Switch or if statements in writing an interpreter in java;他のメンバーがMapを使ってキーワードトークンを削除して実行することを提案しました。変数を保持するための第2の一時的なArrayListまたは配列を設定するのは良い考えですか?私はそれが過度に複雑であることを望まない、または必要としない。

ご提案いただきありがとうございます。

+0

あなたの質問は明確ではありません。 –

+0

@JBNizetメソッドの引数を解析するか、すべての引数を解析して、スクリプトの行を保持しているものとは別のArrayListに配置するかどうかを尋ねていました。 – Luinithil

答えて

1

もし私がそれをやっていたら、より多くのOOアプローチを使用します。

すべてのコマンドが同じインターフェイスを実装しているそれぞれの「クラス」を作成した場合はどうなりますか?インタフェース - CommandObjectにexecute()メソッドを持たせるようにしましょう。

Letクラスのインスタンスに「Let」のようなコマンドをマップしたプリロードされたマップを使用できます。 、シングルトンが働くだろう作るややアンチパターンのである - これらのコマンドは、オブジェクトは変数のセットを共有しなければならない

for(line:lineList) 
    CommandObject commandObject=map.get(line.split()[0]) // do this more clearly 
    commandObject.execute(variableHash, line) // Parse and execute the line 

今、あなたのメインループは次のようなもの(擬似)となり代わりにハッシュマップ(上記のvariableHash)として渡すことをお勧めします。

このアプローチの素晴らしい点は、新しい「コマンド」の追加は非常に単純でほとんど独立していることです。

編集(再コメント。):

あなたはどうしたらまず最初にハッシュマップを作成し、各コマンドの「インストール」です。たとえば、次の(まだpsudeoコード、私はあなたが割り当てを自分で行うことを好むだろうと想定)

map = new HashMap<String, CommandObject> 

、マップに各クラスのインスタンスを追加します。

map.put("LET", new LetCommand()); 
map.put("INTEGER", new Integercommand()); 

右手のクラスは "CommandObject"インタフェースを実装します。

各CommandObjectは、そのキーワードが見つかるたびに再使用されるインスタンスなので、ANY状態(インスタンス変数を持たない)を保存しないほうがよいことに注意してください。これは、CommandObjectには単一この方法は、のようなもの:

execute(String commandLine, HashMap variables); 

これはおそらく最も簡単な方法(私はこれを反映するために、私のオリジナルの提案から上記のテキストを編集した)です。

このパーサがもっと複​​雑になった場合、CommandObjectに多くの機能を追加することは有効です。reset()メソッドを持っていれば状態変数を保持することができます(元の提案ですが、

コマンドオブジェクトへのキーワードのマップは反射で置き換えることはできますが、学校の割り当てにはそれをやろうとしないことに注意してください。反射の複雑さは時間の価値がないので、教師がそれを理解していないので、格下げされる。私はこのようなシステムを実装しています。すべてのキーワードがテストにリンクされています(テストを連鎖させ、テストをループしたり、テストに渡されて操作された変数を定義して持ち歩くことさえできます。新しいテストではキャッシュを更新する必要はありませんでした)

+0

これは私が撮影しようとしていたものです。私は新しいキーワードを追加することがかなり簡単なものを求めていました。しかし、コマンドをハッシュマップとして渡すことについてもっと説明できますか?ありがとう! – Luinithil

+0

ありがとうございます@Bill K、これは素晴らしいです。私はすでにHashMapを開始しています。 – Luinithil

0

正しいデザインは、後でこれらの引数を解析するのをやめるように思えます。 "STRING"や "PRINT"のような特定のコマンドは、空白には依存しないかもしれません。STRING S = "HELLO WORLD"は実際にはSTRING S = "HELLOWORLD"とは機能的に違いはありません。このように "オーバーエンジニアリング"する必要はありません。今のところ最も簡単なことを行い、コマンドクラスの1つまたは2つを書いてから、それらのコマンドクラスが共通して持つものを見つけ出す方が良いでしょう。

これらの引数が特定の方法でリストに解析されることをコマンドのすべて(またはほとんど)が検出した場合、その「リスト解析コード」を静的ユーティリティメソッド(または、継承を使用している場合は、親Commandクラス自体の静的ユーティリティメソッド)。これは、自動テストスイートを作成することに賢明であれば、はるかに危険性は低くなりますが、その種のタスクはスコープ外になる可能性がありますあなたの割り当ての。

0

良い方法の1つは、enumです。そして、私はsplitを2つの項目に制限することを控えていません。

enum Command { 
    LET { 
     @Override 
     public void execute(Context context, String args) { 
     } 
    }, 
    INTEGER { ... }, 
    STRING { ... }, 
    PRINT { ... }, 
    END { ... }; 

    public abstract void execute(Context context, String args); 
} 

private void executeLine(String line) { 
    String[] commandAndArgs = line.split("\\s+", 2); 
    String command = ""; 
    String args = ""; 
    if (commandAndArgs.length > 0) 
     command = commandArgs[0].toUpperCase(); 
    if (commandAndArgs.length > 1) 
     args = commandArgs[1]; 
    Command cmd = Command.valueOf(command); 
    Context context = ...; 
    cmd.execute(context, args); 
} 
関連する問題