编译原理PA1实验报告

余岳 2015011367

环境搭建

  • 我IDE用的intellij,作业所给的框架非常方便,可以直接运行。

实验内容

  • 添加三元操作符 a?b:c
    首先在Lexer.l中定义问号和冒号
"?"  { return operator(Parser.QMARK); }
":"  { return operator(Parser.COLON); }

然后在Parser.yStmt的部分加入一个新的选项

Expr QMARK Expr COLON Expr                    
{
      $$.expr = new Tree.Conditional($1.expr, $3.expr, $5.expr, $2.loc);
}

由于样例中强制要求右结合,故添加token和右结合标记,以及由于优先级的较低,应当写在and和or的上面

%token QMARK COLON
%right QMARK COLON
%left OR
%left AND

之后在tree.java里实现Conditional这个类

    public static class Conditional extends Expr {

        public Expr det;
        public Expr trueval;
        public Expr falseval;

        public Conditional(Expr det, Expr trueval, Expr falseval, Location loc) {
            super(CONDEXPR, loc);
            this.det = det;
            this.trueval = trueval;
            this.falseval = falseval;
        }

        private void ConditionalOperatorPrintTo(IndentPrintWriter pw, String op) {
            pw.println(op);
            pw.incIndent();
            det.printTo(pw);
            trueval.printTo(pw);
            falseval.printTo(pw);
            pw.decIndent();
        }

        @Override
        public void accept(Visitor visitor) {
            visitor.visitConditional(this);
        }

        @Override
        public void printTo(IndentPrintWriter pw) {
            ConditionalOperatorPrintTo(pw, "conditional-expression");
        }
    }

其中要实现它的构造函数和输出格式printTo()
另外需要修改几个小地方:
定义CONDEXPR常量
(注:由于在tree.java里有几个常量的注释中写了原先用的类名,故就用一样的了)

/**
 * Conditional expressions, of type Conditional.
 */
public static final int CONDEXPR = CATCH + 1;

补全visitor的接口

public void visitConditional(Conditional that) {
      visitTree(that);
}
  • switch-case语句
    常量定义等内容和三元表达式一样,下面着重看Parser.y中的写法:
    首先考虑每个case,写出它的格式
Case         : CASE Constant COLON StmtList
DefaultCase  : DEFAULT COLON StmtList

由于有普通case和default case的区别,故在Case构造函数中增加kind以区分,在输出时根据kind不同来区分格式

// Conditioned Case
public Case(int kind, Expr constant, List exprlist, Location loc) {
    super(kind, loc);
    this.constant = constant;
    this.exprlist = exprlist;
}
// Default Case
public Case(int kind, List exprlist, Location loc) {
    super(kind, loc);
    this.exprlist = exprlist;
}

然后若干个case组成的列表,由于优先写左递归,故为了方便将有无default case的情况分开来写成如下形式,其CaseList的具体实现可直接参照StmtList类似地写出。

CaseListWithEnd : CaseList
                  | CaseList DefaultCase
CaseList        : CaseList Case
                  |

于是每个switch语句就可以写成

SwitchStmt      : SWITCH '(' Expr ')' '{' CaseListWithEnd '}'
  • <<运算符、repeat-until循环、continue语句由于比较简单,类似地实现即可

调试遇到的碰到的坑

  • 在写switch-case语句的时候,由于在三元运算符时将冒号:转为COLON,故不能将Case写成
Case            : CASE Constant ':' StmtList
  • parser.y中的常量全部需要用单引号
  • 目前还不知道如何开启byacc的yydebug模式,这给调试带来了不少麻烦,只能手动输出调试,感觉需要进一步研究一下它的架构。

你可能感兴趣的:(编译原理PA1实验报告)