自学就是痛苦啊,都不知道构造出的是不是抽象语法树。

  首先,前面两篇给出的语法文件里有错误,不能连续进行let in end的声明。(主要是tiger的语法太怪,虎书上在第3章又没有给出完整的yacc文件,让读者自己添加。这样好处是让读者自己动手,但是后果是自己添加的很多名称以及过程与后续章节不同,会有一点麻烦。)

  修改如下:

<Decs> ::= <Dec> <Decs>
         | 'let' <Decs> 'in' <Stm> 'end' [color=FF0000]<Decs>[/color]
         |

既在'end'后再添加<Decs>,这样便可以连续声明let in end。

  Gold Parser中的语法树构造,主要是在终止符和非终止符读取时进行用户Object的构造。

        private Object CreateObject(Token token)
        {
            if (token is TerminalToken)
                return CreateObjectFromTerminal((TerminalToken)token);
            else
                return CreateObjectFromNonterminal((NonterminalToken)token);
        }

  终止符的读取主要是int和string的读取(应该还包括一切转义字符,特殊字符,我的程序里只处理了前两种),非终止符是在Reduce时处理。比如下面的代码演示了在进行Decs相关的Reduce时的处理,创建了新类Decs。

                case (int)RuleConstants.RULE_DECS :
                //<Decs> ::= <Dec> <Decs>
                //todo: Create a new object using the stored tokens.
                    return new Decs((Dec)token.Tokens[0].UserObject,(Decs)token.Tokens[1].UserObject);


                case (int)RuleConstants.RULE_DECS_LET_IN_END :
                    //<Decs> ::= let <Decs> in <Stm> end <Decs>
                //todo: Create a new object using the stored tokens.
                    return new Decs((Decs)token.Tokens[1].UserObject, (Statement)token.Tokens[3].UserObject,(Decs)token.Tokens[5].UserObject);
                
  所以写个编译器真的是比较麻烦。至少每个非终止符都要进行处理。

  C++代码中用enum及union比较方便,可惜C#中没有union,只有用类代替了。比如Dec类代码如下:

    public class Dec
    {
        public VarDec vardec;
        public Dec(VarDec vardec)
        {
            this.vardec=vardec;
        }
        public FunctionDec functiondec;
        public Dec(FunctionDec functiondec)
        {
            this.functiondec=functiondec;
        }
        public FieldDec fielddec;
        public Dec(FieldDec fielddec)
        {
            this.fielddec=fielddec;
        }
        public TypeDec typedec;
        public Dec(TypeDec typedec)
        {
            this.typedec=typedec;
        }

};

  怎么查看生成的抽象语法树呢?我是在<Start> ::= <nl Opt> <Decs>这一句时,返回Decs,也不知道对不对。下面来对比下具体语法树和抽象语法树的区别。

  在Gold Parser中输入如下tiger代码(很简单,但是足以后续进行构造符号表和进行类型、范围检查。我实在是懒得实现tiger的所有语法了。:()

let
    var N := 8
in try(0)
end

let
    var M := 80
in try(1)
end

    GoldParser的语法测试功能显示的树结构如下:

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

  而在VS2005中通过调试功能显示的树状结构如下(其中很多值为null的结点是浪费的,但是没折,没有union。)

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

两者最主要的区别:前者在节点中包含“let”“int”“end”“var”“:=”等符号,但是它们对最终运算是无用的。抽象语法树的叶节点只包含非终止符,将其它的所有信息包含在了内部节点中。

  现在感觉难度越来越大了,下一章会构造符号表,并进行最简单的类型检查。代码就不上传了,会误导人的。(btw:非常希望得到熟悉编译原理的朋友给我指点!)