C#(我自己的编程语言) - 如何在解析时多次查找 PRINT STRING
本文关键字:STRING PRINT 查找 自己的 我自己 编程语言 | 更新日期: 2023-09-27 17:56:21
所以我目前正在基于 how Code 的 Python 编程语言制作自己的编程语言,但我只花了一个小时左右的时间尝试将其转换为 C#,它很棒,尽管当我告诉解析我们收集的令牌时,它只在找到 PRINT STRING 或令牌后解析一次, 然后就停了下来,
这是我的解析器、词法分析器、我的语言脚本和控制台的代码:
解析 器:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BL
{
public static class Parser
{
public static void Parse(string toks)
{
if (toks.Substring(0).Split(':')[0] == "PRINT STRING")
{
Console.WriteLine(toks.Substring(toks.IndexOf(''"') + 1).Split(''"')[0]);
}
}
}
}
词法分析器:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BL
{
public static class Lexer
{
public static string tok = "";
public static string str;
public static int state = 0;
public static string tokens = "";
public static void Lex(string data)
{
foreach (char c in data)
{
tok += c;
if (tok == " ")
{
if (state == 0)
{
tok = "";
tokens += " ";
}
else if (state == 1)
{
tok = " ";
}
}
else if (tok == Environment.NewLine)
{
tok = "";
}
else if (tok == "PRINT")
{
tokens += "PRINT";
tok = "";
}
else if (tok == "'"")
{
if (state == 0)
{
state = 1;
}
else if (state == 1)
{
tokens += "STRING:" + str + "'" ";
str = "";
state = 0;
tok = "";
}
}
else if (state == 1)
{
str += tok;
tok = "";
}
}
Parser.Parse(tokens);
}
}
}
我的脚本:
PRINT "HELLO WORLD1"
PRINT "HELLO WORLD2"
控制台:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace BL
{
class Program
{
static string data;
static void Main(string[] args)
{
Console.Title = "Compiler";
string input = Console.ReadLine();
Open(input);
Lexer.Lex(data);
Console.ReadLine();
}
public static void Open(string file)
{
data = File.ReadAllText(file);
}
}
}
当我打印令牌的内容(在 Lexer 中)时,我得到这个:
PRINT STRING:"HELLO WORLD1" PRINT STRING:"HELLO WORLD2"
虽然当我解析它时,它只打印 HELLO WORLD1,而不是 HELLO WORLD1 和它下面的 HELLO WORLD2,我不确定我应该怎么做才能获得另一个 PRINT STRING,显然因为这是一个只有我创建的项目,网上没有答案,提前谢谢。
您正在尝试解析该语言,这很好,但随后您将生成第二种编程语言。 这意味着您的 Lex() 函数最终将需要它自己的解析逻辑来处理生成的文本。
这就是为什么大多数时候这类问题得到解决时,Lex() 函数将创建一个令牌列表供其他人使用。 通常,这些标记不仅仅是字符串,但对于许多小语言来说,可以使用简单的字符串列表作为标记。
由于我对玩具语言情有独钟,因此我修改了您的示例以遵循此流程。 它从用户输入加载文件,然后将其分解为单独的令牌,并使用这些令牌"运行"程序:
// Parse a list of tokens from Lex()
static void Parse(List<string> tokens)
{
// Run through each token in the list of tokens
for (int i = 0; i < tokens.Count; i++)
{
// And act on the token
switch (tokens[i])
{
case "PRINT":
// PRINT prints the next token
// Move to the next token first
i++;
// And dump it out
Console.WriteLine(tokens[i]);
break;
default:
// Anything else is an error, so emit an error
Console.WriteLine("ERROR: Unknown token " + tokens[i]);
break;
}
}
}
// Parse a source code file, returning a list of tokens
static List<string> Lex(string data)
{
// The current token we're building up
string current = "";
// Are we inside of a quoted string?
bool inQuote = false;
// The list of tokens to return
List<string> tokens = new List<string>();
foreach (char c in data)
{
if (inQuote)
{
switch (c)
{
case '"':
// The string literal has ended, go ahead and note
// we're no longer in quote
inQuote = false;
break;
default:
// Anything else gets added to the current token
current += c;
break;
}
}
else
{
switch (c)
{
case '"':
// This is the start of a string literal, note that
// we're in it and move on
inQuote = true;
break;
case ' ':
case ''n':
case ''r':
case ''t':
// Tokens are sperated by whitespace, so any whitespace
// causes the current token to be added to the list of tokens
if (current.Length > 0)
{
// Only add tokens
tokens.Add(current);
current = "";
}
break;
default:
// Anything else is part of a token, just add it
current += c;
break;
}
}
}
return tokens;
}
// Quick demo
static void Main(string[] args)
{
string input = Console.ReadLine();
string data = File.ReadAllText(input);
List<string> tokens = Lex(data);
Parse(tokens);
Console.ReadLine();
}