PA3 Parser
PA3要求我们实现语法分析器。
所需要的文法已经在cool-manual
中第10节下面的图片中给出了,我们只需要根据这个写出相应的代码即可,了解一下bison
语法以及如何在代码中创建节点就可以开始了。
得分:
下面是一些我在做的过程中遇到的需要注意的地方:
- 这个
bison
了解一下基本的语法就可以了,不用面面俱到,bison
文档很长,在读bison
文档时应该把握主要的脉络,不用太在意细节,读2、3章,再学习一下LR
文法和第5章就够了。 - debug的时候程序尽量简短,因为它展示出来的过程会很长。
符号优先级
符号优先级可以在cool-manual
的第11节中找到,在代码中实现如下:
%right ASSIGN
%left NOT
%nonassoc LE '<' '='
%left '+' '-'
%left '*' '/'
%left ISVOID
%left '~'
%left '@'
%left '.'
注意优先级越高要写到越下面。
非终结符声明
要使用上下文无关文法,首先要定义非终结符,如下:
%type <program> program
%type <classes> class_list
%type <class_> class
/* You will want to change the following line. */
%type <features> feature_list
%type <feature> feature
%type <formals> formal_list
%type <formal> formal
%type <expressions> blocks
%type <expressions> expression_list
%type <expression> let_expr
%type <expression> expression
%type <cases> case_list
%type <case_> case
文法
开始写文法,根据老师提供的文法规则,按顺序实现如下。
program和class
这块老师已经写了一部分,补充完整如下:
program :
class_list {
@$ = @1;
ast_root = program($1);
}
;
class_list:
class {
$$ = single_Classes($1);
parse_results = $$;
}
| class_list class {
$$ = append_Classes($1,single_Classes($2));
parse_results = $$;
}
;
/*补充class的表达式*/
class:
CLASS TYPEID '{' feature_list '}' ';' {
$$ = class_($2,idtable.add_string("Object"),$4,
stringtable.add_string(curr_filename));
}
| CLASS TYPEID INHERITS TYPEID '{' feature_list '}' ';' {
$$ = class_($2,$4,$6,
stringtable.add_string(curr_filename));
}
| CLASS error ';' class {
$$ = $4;
}
;
上面的报错是简单版本的,直接跳过当前错误的类并到下一个类,但这就产生了一个问题,如果出错的类是最后一个,该规则就不匹配了(虽然也没什么问题)。为此,可以将报错规则修改为对当前类各个组成部分检查错误,如果有错,就忽略当前类,但不跳至下一个:
| error TYPEID INHERITS TYPEID '{' feature_list '}' ';'
| CLASS error INHERITS TYPEID '{' feature_list '}' ';'
| CLASS TYPEID error TYPEID '{' feature_list '}' ';'
| CLASS TYPEID INHERITS error '{' feature_list '}' ';'
| CLASS TYPEID INHERITS TYPEID error feature_list '}' ';'
| CLASS TYPEID INHERITS TYPEID '{' feature_list error ';'
这两种在测试中都得到了满分。
feature
feature
表示的是类中的语句,feature
和class
报错写法不同的主要原因是一个允许为空而另一个不允许,。
feature_list: // [feature;]*
{ $$ = nil_Features(); }
| feature_list feature {
$$ = append_Features($1, single_Features($2));
}
| feature_list error ';' {
$$ = $1;
}
;
feature:
OBJECTID '(' ')' ':' TYPEID '{' expression '}' ';' {
$$ = method($1, nil_Formals(), $5, $7);
}
| OBJECTID '(' formal_list ')' ':' TYPEID '{' expression '}' ';' {
$$ = method($1, $3, $6, $8);
}
| OBJECTID ':' TYPEID ';' {
$$ = attr($1, $3, no_expr());
}
| OBJECTID ':' TYPEID ASSIGN expression ';' {
$$ = attr($1, $3, $5);
}
;
formal
formal
表示函数的输入参数列表,formal_list
不为空。
formal_list:
formal {
$$ = single_Formals($1);
}
| formal_list ',' formal {
$$ = append_Formals($1, single_Formals($3));
}
;
formal:
OBJECTID ':' TYPEID {
$$ = formal($1, $3);
}
blocks
expression
即表达式,在下面说明。
blocks
为表达式列表的一种形式。
blocks: // [expression;]+
expression ';' {
$$ = single_Expressions($1);
}
| blocks expression ';' {
$$ = append_Expressions($1, single_Expressions($2));
}
| blocks error ';' {
$$ = $1;
}
;
expression_list
表达式列表的另一种形式。
expression_list: // expression(,expression)*
expression {
$$ = single_Expressions($1);
}
| expression_list ',' expression {
$$ = append_Expressions($1, single_Expressions($3));
}
;
let_expr
let_expr
表示上面画红线的那部分。
let_expr:
OBJECTID ':' TYPEID IN expression {
$$ = let($1, $3, no_expr(), $5);
}
| OBJECTID ':' TYPEID ASSIGN expression IN expression {
$$ = let($1, $3, $5, $7);
}
| OBJECTID ':' TYPEID ',' let_expr {
$$ = let($1, $3, no_expr(), $5);
}
| OBJECTID ':' TYPEID ASSIGN expression ',' let_expr {
$$ = let($1, $3, $5, $7);
}
| error ',' let_expr {
$$ = $3;
}
;
case
case_list:
case {
$$ = single_Cases($1);
}
| case_list case {
$$ = append_Cases($1, single_Cases($2));
}
;
case:
OBJECTID ':' TYPEID DARROW expression ';' {
$$ = branch($1, $3, $5);
}
;
expression
按照给定的规则写就可以了,这里不用报错:
expression:
OBJECTID ASSIGN expression {
$$ = assign($1, $3);
}
| expression '.' OBJECTID '(' ')' {
$$ = dispatch($1, $3, nil_Expressions());
}
| expression '.' OBJECTID '(' expression_list ')' {
$$ = dispatch($1, $3, $5);
}
| expression '@' TYPEID '.' OBJECTID '(' ')' {
$$ = static_dispatch($1, $3, $5, nil_Expressions());
}
| expression '@' TYPEID '.' OBJECTID '(' expression_list ')' {
$$ = static_dispatch($1, $3, $5, $7);
}
| OBJECTID '(' ')' {
$$ = dispatch(object(idtable.add_string("self")), $1, nil_Expressions());
}
| OBJECTID '(' expression_list ')' {
$$ = dispatch(object(idtable.add_string("self")), $1, $3);
}
| IF expression THEN expression ELSE expression FI {
$$ = cond($2, $4, $6);
}
| WHILE expression LOOP expression POOL {
$$ = loop($2, $4);
}
| '{' blocks '}' {
$$ = block($2);
}
| LET let_expr {
$$ = $2;
}
| CASE expression OF case_list ESAC {
$$ = typcase($2, $4);
}
| NEW TYPEID {
$$ = new_($2);
}
| ISVOID expression {
$$ = isvoid($2);
}
| expression '+' expression {
$$ = plus($1, $3);
}
| expression '-' expression {
$$ = sub($1, $3);
}
| expression '*' expression {
$$ = mul($1, $3);
}
| expression '/' expression {
$$ = divide($1, $3);
}
| '~' expression {
$$ = neg($2);
}
| expression '<' expression {
$$ = lt($1, $3);
}
| expression LE expression {
$$ = leq($1, $3);
}
| expression '=' expression {
$$ = eq($1, $3);
}
| NOT expression {
$$ = comp($2);
}
| '(' expression ')' {
$$ = $2;
}
| OBJECTID {
$$ = object($1);
}
| INT_CONST {
$$ = int_const($1);
}
| STR_CONST {
$$ = string_const($1);
}
| BOOL_CONST {
$$ = bool_const($1);
}
;