1

私はC#でCocoRサンプルTasteを使用しています。

次のような操作が与えられたときに文字列を書くためにコードを拡張しようとしています

HelloWorldを書く

文字列を保存および書き込む方法を特定しました。私が抱えている問題に関連するコードを出している:

拡張されたTaste.ATG

| "write" 
    { Expr<out type>    (. if (type != integer) SemErr("integer type expected");
                            gen.Emit(Op.WRITE); .)
    | '"' 
    ident       (. name = Convert.ToString(t.val);
                            gen.Emit(Op.READS);
                            gen.Emit(Op.WRITES).)
    '"'
    }';'

CodeGen.csの拡張操作:Filestreamはこのように使用されます

public void Interpret (string data) { 
    int val;
    try {
        FileStream s = new FileStream(data, FileMode.Open);
        Console.WriteLine();
        pc = progStart; stack[0] = 0; top = 1; bp = 0;

ファイルストリームを使用するケーススイッチを追加しました

case Op.READ:  val = ReadInt(s); Push(val); break;
case Op.READS: stackString[index] = ReadString(s) ; Push(index); index++; break;
case Op.WRITE: Console.WriteLine(Pop()); break;
case Op.WRITES: Console.WriteLine(stackString[Pop()]); break;

問題は、文字列を読み取る方法がインターネット上のどこにも見つからないことです。明らかにReadString(s)、同じようにReadInt(s)は機能しません。ファイルストリームから文字列を読み取る操作を見つけるための助けを得ることができるかどうか疑問に思いました。

私はこれまでファイルストリームの管理を行ったことがありません。

4

1 に答える 1

2

EDIT3 このようなものをもう一度調べた後、私はこのアプローチに大きな問題があることに気づきました。最初にいくつかの説明をします。Coco/Rはatgファイルからスキャナーとパーサーを生成します。Taste.csのメインプログラムはこれらを使用してTaste.TASをコンパイルします。

コンパイルされたTaste.TASは、仮想マシンのように受信したオペコードを処理するCodeGen.csのInterpretメソッドに送られるため、このReadInt()メソッドは、コンパイルされたTaste.TASのサンプルデータを含むTaste.INから読み取ることになっています。プログラム。

したがって、CodeGen.csでHello Worldのサポートを追加するには、Interpretメソッドを変更するだけでは不十分です。コンパイラがコンパイル時に文字列を追加できるように、Emitメソッドにもパッチを適用する必要があります。

いつものようにハッキー(CodeGen.csに入ります):

List<string> strStack = new List<string>();
public void Emit(Op op, string str)
{
    int idx = strStack.Count;
    strStack.Add(str);
    Emit(op, idx); // adds the opcode, 
}

Taste.ATGで、書き込み命令を次のように変更する必要があります。Gen.Emit(Op.WRITES, t.val);

また、Interpretメソッドでは、文字列リストへの参照を使用する必要があります。

case Op.WRITES: Console.WriteLine(strStack[Next2()]); break;

EDIT4-将来の参照のStreamReaderためにファイルから文字列リテラルを読み取るには、次のようにクラスを使用できます。

    /// <summary>
    ///     Reads a string literal from a file, essentially implementing the regex pattern /\"{.*}\"/.
    ///     Ignores escape characters (for instance, "\"" will fail)
    /// </summary>
    /// <param name="fs">The file stream to read from.</param>
    /// <returns>The string literal without it's quotes upon success, null otherwise.</returns>
    static string ReadString(FileStream fs)
    {
        if (!fs.CanRead)
            return null; // cant read from stream, throw an exception here

        var reader = new StreamReader(fs);
        var sb = new StringBuilder();

        bool inString = false;

        while (true)
        {
            if (reader.Peek() < 0)
                return null; // reached EOF before string ended, throw exception here

            char ch = (char)reader.Read();

            if (inString)
                if (ch == '"')
                    break;
                else
                    sb.Append(ch);
            else
                if (ch == '"')
                    inString = true;
                else if (!char.IsWhiteSpace(ch))
                    return null; // string does not start with quote, throw exception here
        }

        return sb.ToString();
    }

別の方法は[ Regex][3]クラスを使用することですが、デフォルトでは文字列でのみ機能するため、複数行にまたがる文字列を取得するには、トリッキーな読み取りとシーク操作が必要です(サポートされている場合)。プログラムの残りのファイルストリーム。

于 2011-12-26T21:44:27.033 に答える