我在C#中使用Coco R样本Taste。
我正在尝试扩展代码以在给出操作时编写字符串,例如
写 hello world
我已经确定了一种可以存储和编写字符串的方法。我正在为我遇到的问题提出相关代码:
扩展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)
的工作方式不同{{1}}。
我想知道我是否可以帮助找到一个从文件流中读取字符串的操作。
我之前没有做过任何文件流管理。
答案 0 :(得分: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中,您必须将写入指令更改为Gen.Emit(Op.WRITES, t.val);
在Interpret-method中,您需要使用对字符串列表的引用:
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]类,但由于它默认只适用于字符串,因此需要一些棘手的读取和搜索操作来获取跨越多行的字符串(如果支持),所以你不要为程序的其余部分提供文件流。