余岳 2015011367
环境搭建
- 我IDE用的intellij,作业所给的框架非常方便,可以直接运行。
实验内容
- 添加三元操作符 a?b:c
首先在Lexer.l
中定义问号和冒号
"?" { return operator(Parser.QMARK); }
":" { return operator(Parser.COLON); }
然后在Parser.y
中Stmt
的部分加入一个新的选项
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
模式,这给调试带来了不少麻烦,只能手动输出调试,感觉需要进一步研究一下它的架构。