C# Файловый поток чтения строк (Coco/R Taste)
Я работаю с Coco R образец вкуса, в C#.
Я пытаюсь расширить код для записи строк, когда дается такая операция, как
напиши привет мир
Я определил способ, которым я могу хранить и записывать строки. Я выкладываю соответствующий код для проблемы, которую я имею:
Расширенный вкус.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: таким образом используется файловый поток
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 ответ
РЕДАКТИРОВАТЬ3 После повторного изучения этого материала, я обнаружил большую проблему с этим подходом. Прежде всего поясним: Coco/R генерирует сканер и анализатор из файла atg, основная программа в Taste.cs использует их для компиляции Taste.TAS.
Скомпилированный Taste.TAS затем подается в метод Interpret CodeGen.cs, который обрабатывает коды операций, которые он получает как виртуальная машина, поэтомуReadInt()
Метод должен читать из Taste.IN, который содержит примеры данных для скомпилированной Taste.TAS-программы.
Таким образом, чтобы добавить поддержку hello world в CodeGen.cs, недостаточно изменить метод 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], но поскольку он по умолчанию работает только со строками, он требует некоторых сложных операций чтения и поиска для получения строк, занимающих несколько строк (если поддерживается), поэтому вы не добавляете поток файлов для остальной части программы,