本篇来讲讲怎么将GOLD Parser集成到我们自己的程序中。工科出生,关键就是要会用。这次会建立一个简单的.net程序,用户输入Tiger源代码后,会显示语法分析的状态。最终的程序名叫fisrtParser,主界面如下,在.net 2.0下编译运行。
 
[IMG]http://bbs.pediy.com/upload/2006/37/image/1.jpg_600.jpg[/IMG] 

接着第一篇说,我们已经得到了tiger1.grm,并将其编译成了tiger1.cgt(cgt应该是指Compiled Grammar Table)。GP的工作流程分两段,先是生成cgt,然后选择合适的engine来集成到我们的程序中。这里,我们选择GP自带的引擎。
在菜单中选择:Create a Skeleton Program,随后在弹出窗口中选择:Calitha Engine。是不是Event Based的,现在不重要,这里为统一,选择Event Based。
 
[IMG]http://bbs.pediy.com/upload/2006/37/image/2.jpg_633.jpg[/IMG]

单击Create后,便会生成一个框架C#代码文件,我们将它命名为TigerEngine.cs,这个文件便是我们要实现的自已的Parser的框架代码。
新建工程fisrtParser,将TigerEngine.cs加进来。不过GP的工作流程和yacc产生的文件不一样,yacc生成的C或C++代码中包含了parser的全部代码,而TigerEngine.cs中只包含框架,真正的实现是在Engine的几个dll中。也就是说,必须在我们的工程里添加对Calitha Engine的引用,最终生成的exe文件也会带着engine的dll运行。(当然,你也可以将engine的代码加入自己的project,而不是引入project,这样只生成一个exe文件了。)
另一点要注意的就是,必须将tiger1.cgt包含在我们的工程中,并定义为“Embedded Resource”,因为对engine初始化时,必须传入cgt文件。最终的VS工程文件如下所示:
 
[IMG]http://bbs.pediy.com/upload/2006/37/image/3.jpg_674.jpg[/IMG] 

主程序界面上建立一个文件框textBoxSrc用于输入源码,一个textBoxLog用于显示parse的结果,两个button控件。下面便可以进行TigerEngine的使用了。
总的来说,这个框架代码的使用还是比较简单的,总的来说分两步:首先传入cgt对engine进行初始化,然后传入源代码进行分析。button1控件的代码显示了整个步骤。

private void button1_Click(object sender, EventArgs e)
        {
            textBoxLog.Clear();
            parseResult = null;
            MyParser parser = new MyParser(Assembly.GetExecutingAssembly().GetManifestResourceStream("firstParser.tiger1.cgt"));            
            parser.Parse(textBoxSrc.Text);            
            textBoxLog.Text = parseResult;        
        }

其实这样就已经OK了,但是运行后程序没有任何反应。当然,要想让程序有反应,我们要在框架代码中动动手脚,毕竟,它只是个框架。对了,在编写这些代码前,需要添加对engine代码和TigerEngine的引用,因此不要忘了在程序前加上:
using com.calitha.goldparser;
using com.calitha.commons;

首先在主窗口类中加入一个string parseResult,用于显示分析的结果。定义如下:
public static string parseResult;

下面就得进入TigerEngine.cs中,添加代码,为parseResult显示信息。刚才我们选择了Event Based,代表对源代码的分析过程中,会有一系列的事件(读入token,出错,结束等),默认已经定义的三个事件如下:
            parser.OnTokenError += new LALRParser.TokenErrorHandler(TokenErrorEvent);
            parser.OnParseError += new LALRParser.ParseErrorHandler(ParseErrorEvent);
          parser.OnAccept += new LALRParser.AcceptHandler(AcceptEvent);

由于虎书刚看到第3章,不要求在代码中加入Semantic Actions,因此我们就在程序中简单的显示这三个事件的信息吧。
分别在这三个方法的代码中添加对parseResult的操作:
        private void TokenErrorEvent(LALRParser parser, TokenErrorEventArgs args)
        {
            args.Continue = true;
            string message = "Token error with input: '"+args.Token.ToString()+"'";
            Form1.parseResult += message+"\r\n";
            //todo: Report message to UI?
        }

        private void ParseErrorEvent(LALRParser parser, ParseErrorEventArgs args)
        {            
            string message = "Parse error caused by token: '"+args.UnexpectedToken.ToString()+"'";
            message += "token skiped!";
            args.Continue = ContinueMode.Skip;
            Form1.parseResult += message+"\r\n";
            //todo: Report message to UI?
        }

        private void AcceptEvent(LALRParser parser, AcceptEventArgs args)
        {
            string message = "Parse Finished!\r\n";
            Form1.parseResult += message;
            Form1.tokens = args.Token.Tokens;            
            //todo: Report message to UI?
        }

其中比较有意思的是Error既出错的处理,这里进行了简单地错误处理,既跳过出错的token,继续进行分析。你可认利用args中提供的更多信息,进行更复杂的错误处理,这里就不深入了。
编译后,可以试验我们的程序了。在文本框中键入一句标准的tiger中的赋值语句:
var N := 8
点击Parse后,状态窗口中显示“Parse Finished!”,这正是我们在Accept事件中要求显示的信息。下面改变一下代码,来看看出错信息的显示。重新输入:
编译
var N := 8
varr M := 9

再次点击Parse后,Log窗口中显示的信息如下:
Token error with input: '编'
Token error with input: '译'
Parse error caused by token: 'varr'token skiped!
Parse error caused by token: 'M'token skiped!
Parse Finished!

[IMG]http://bbs.pediy.com/upload/2006/37/image/4.jpg[/IMG]

信息告诉了我们,“编译”两个字不是合法的token,因此在词法分析阶段就被K掉了。由于我们设置了遇错后继续,因此词法分析没有停止。其次是“varr”不是合法的token,被跳过,而因为varr被跳过,因此M打头的语句也是不合法的,因此M也被跳过。
由于程序没有实现树状显示Parse Tree的功能,因此只能到这一步了。虎书的第四章介绍了Abstract Syntax Tree,看完后应该能够给程序加上Semantic Actions的代码了。那是后话。Calitha引擎完全开源,并且附带了一个很好的示例,有兴趣的可以自己阅读。(写本文没看它的文档,也就是参考了示例中的源码。)

本文就到这里,附件里提供了firstTiger的可执行文件,必须在.net 2.0下运行。下一篇会学什么呢?应该是添加Semantic Actions吧。
(同样,无法上传附件,需要下载附件的请去我的BLOG,[url]http://vxer.cn/blog[/url])