C# 文件流读取字符串(Coco/R Taste)

发布于 2024-12-22 23:03:14 字数 1264 浏览 1 评论 0原文

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

我正在尝试扩展代码以在给出诸如

write hello world

之类的操作时写入字符串,我已经确定了一种可以存储和写入字符串的方法。我针对我遇到的问题发布了相关代码:

Expanded 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).)
    '"'
    }';'

Expanded Operations in CodeGen.cs: 文件流以这种方式使用

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) 不同。 我想知道是否可以获得帮助来查找从文件流读取字符串的操作。

我以前没有做过任何文件流管理。

I'm working with Coco R sample Taste, in C#.

I'm trying to expand the code to write Strings when an operation is given such as

write hello world

I have identified a way, in which I can store and write strings. I'm putting out relevant code for the problem I'm having:

Expanded 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).)
    '"'
    }';'

Expanded Operations in CodeGen.cs:
Filestream is used in this way

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;

and added case switches, that use filestream

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;

The problem is, I cant find anywhere on the internet a way to read a String,
clearly ReadString(s) doesn't work the same way ReadInt(s) does.
I was wondering if I can get help to find an operation, that reads a string from the file stream.

I haven't done any filestream management before.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

粉红×色少女 2024-12-29 23:03:14

编辑3
再次研究这个东西后,我发现这种方法有一个更大的问题。首先解释一下: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);

并在 Interpret 中-方法,您将需要使用对字符串列表的引用:

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

EDIT4 - Just for future reference 要从文件中读取字符串文字,您可以使用

    /// <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();
    }

href="http://msdn.microsoft.com/en-us/library/system.io.streamreader.aspx" rel="nofollow">StreamReader类 另一种方法是使用 [Regex][3] 类,但由于默认情况下它仅适用于字符串,因此需要一些棘手的读取和查找操作来获取跨越多行的字符串(如果支持) ),这样你就不用担心程序其余部分的文件流。

EDIT3
After looking into this stuff again, I found a bigger problem with this approach. First off some explanation: Coco/R generates the scanner and parser from the atg file, the main program in Taste.cs uses these to compile the Taste.TAS.

The compiled Taste.TAS is then fed into the CodeGen.cs's Interpret method which works down the opcodes it receives like a virtual machine, so it's ReadInt() method is supposed to read from Taste.IN, which contains sample data for the compiled Taste.TAS-program.

So, to add support for a hello world in the CodeGen.cs, it is not enough to change the Interpret method, you will have to patch the Emit method as well, to allow the compiler to add the string at compile-time.

Hacky as always (goes into 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, 
}

In the Taste.ATG you will have to change the Write-instruction to Gen.Emit(Op.WRITES, t.val);

And in the Interpret-method, you will need to use the reference to the string list:

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

EDIT4 - Just for future reference To read a string literal from a file you could use the StreamReader class like so:

    /// <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();
    }

An alternative would be to use the [Regex][3] class, but since it by default only works with strings, it requires some tricky read-and-seek operations to get strings spanning multiple lines (if supported), so you do not fubar the filestream for the rest of the program.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文