二、预处理
开始写代码吧,用什么语言好呢?C、C++、Java、C#?
随便,什么顺手就用什么,语言只是工具而已。
这学期开了一门新课,.Net程序设计,接触了C#,那就那它吧,也好熟悉这么语言
新建一个工程Snail(慢慢来的意思~哈哈),添加一个文件main.cs
代码如下:
namespace Snail
{
public static void Main()
{
Console.Read();
}
}
这就是入口函数了,相当于C的main函数
既然我们要做预处理,那单独建一个类吧,但我们不急着编写代码,而是想想它是怎么工作的。
既然我们是解释型脚本,做词法分析的时候,肯定不能一次性的就分析完了吧,肯定是边运行,边分析。为了加快速度和简化词法分析,所以需要预处理,把一长串的代码,分成一个个单独的字符串
好,我大概想到了
首先,我们需要一个虚拟机(别被名字忽悠了,没那么高深)
新建一个Snail.cs写一点基本的代码
public class Snail
{
public Snail()
{
}
public void Execute(string code)
{
}
}
然后在Main函数里写入
Snali s = new Snail();
string code = File.ReadAllText(“test.txt”); // 把文件test.txt的内容全读取到code中
s.Execute(code);
编译是可以的,不过估计运行错误,因为没有test.txt。当然,你可以在程序目录创建一个test.txt,这样运行是没有错了,但什么也不会显示,因为代码什么都没做。别急,下一步,我们开始预处理
新建一个Lexel.cs文件
public class Lexel
{
public Lexel()
{
}
public void Start(string code)
{
}
}
Start(本来想改Pretreatment的,但这单词太难打了)函数负责处理传入的参数code,那么这个函数需要完成什么样的功能呢?
我想把脚本的代码分解为一个个小的字符串,每个字符串为一个基本单位,称为Token。
那依据什么来分割字符串呢?
对于如下代码
def_main
@x = 10;
end
可以用符号_ @ ; =和空格等来分割
其中,这些符号是需要的,就是说,它不只起到分割Token的作用,它本事也是一个Token。
还有一些,比如空格,仅仅起到一个分割Token的作用
好,有了这么一个基本的概念。可以动手写代码了
首先,申明两个数组
private char[] invalidSigns = new char[]{ ‘\r’, ‘\n’, ‘ ’, ‘\t’ };
这些字符是不需要的,仅仅起到分割作用
private char[] splitSigns = new char[]
{
‘_’, ‘@’, ‘=’, ‘;’
};
然后在申请一个
private List<string> Tokens = new List<string>(); // 不了解C#的朋友,可以当它是一个队列,或者说是C的链表吧~差不多的
好了,有了这两个数组和一个List,我们可以开始编写Start函数了
下面有些东西,比如StringBuilder和foreach,不了解的,可以百度下C#的知识,以后就不单独解释这些东西了
public void Start(string code)
{
try
{
StringBuilder line = new StringBuilder();
// 分析每一个字符
foreach ( char c in code )
{
// 如果这个字符在invalidSigns数组中
// 那么说明这个字符是一个分割字符,而且本身不被程序需要
if ( invalidSigns.Contains<char>(c))
{
// 添加字符串到Token中
if ( line.Length != 0 )
{
Tokens.Add(line.ToString());
Tokens.Clear();
}
continue;
}
// 如果这个字符在splitSigns数组中
// 那么说明这个字符是一个分割字符,本身被程序所需要
if ( splitSigns.Contanis<char>(c) )
{
// 添加字符串到Tokens中
if ( line.Length != 0 )
{
Tokens.Add(line.ToString();
Tokens.Clear();
}
// 添加这个分隔符本身到Tokens中
Tokens.Add(c.ToString());
}
}
}
catch(Exception ex) // 异常处理(关于这个,可百度之~)
{
throw ex;
}
}
代码很简短,因该能表达的清楚吧。
意思很简单,把一长串的代码,分成我想要的Tokens
测试下:
在test.txt中输入
def_main
@x=10;
end
在Snail的Execute中(不会忘记了吧,这可是我们的虚拟机,在main函数中被调用)输入
Lexel lexel = new Lexel();
lexel.Start(code);
foreach (string token in lexel.Tokens) // 为了测试,把Tokens的private改为public
{
Console.WriteLine(token);
}
运行结果
def
_
main
@
x
=
10
;
end
成功。下一步开始词法分析