1

我正在使用 C# 中的 Coco R 示例 Taste。

当给出操作时,我正在尝试扩展代码以编写字符串,例如

你好世界

我已经确定了一种可以存储和编写字符串的方法。我正在为我遇到的问题发布相关代码:

扩展的味道

| "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.IN 中读取,其中包含编译后的 Taste.TAS 的示例数据-程序。

因此,要在 CodeGen.cs 中添加对 hello world 的支持,仅更改 Interpret 方法是不够的,您还必须修补 Emit 方法,以允许编译器在编译时添加字符串。

Hacky 一如既往(进入 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 中,您必须将 Write-instruction 更改为Gen.Emit(Op.WRITES, t.val);

在解释方法中,您需要使用对字符串列表的引用:

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] 类,但由于默认情况下它仅适用于字符串,因此它需要一些棘手的读取和查找操作来获取跨越多行的字符串(如果支持),所以你不要 fubar程序其余部分的文件流。

于 2011-12-26T21:44:27.033 回答