Compiler 2014: Mail List Summary Phase 2
中期检查
语法支持gcc不支持的请一律报错即可
数据是一样的,周六周日都会测,取两次的最高分
makefile和midtermvars.sh是自己提供的
we regard the 'midterm' tag as your submitted version, so don't forget to push the tags.
statspim下载
https://bitbucket.org/xjia/statspim
semantic analysis 和 translation
Q:
应该如何处理这两部分?
A:
semantic analysis 和 translation 可以分开写,也可以在一起写
我记得虎书上是先让你写 semantic analysis,然后接下来让你修改代码,加入 translation 的功能;我这样写过一次,后来觉得有点乱
所以我第二次写的时候把两部分分开了,semantic analysis 的时候完全是判断是不是符合语言使用规则,translation 的时候就可以认为目前的输入一定正确了,
写起来会简单一些
semantic analysis 得到的类型信息可以添加到 AST 上,叫做 annotated parse tree,龙书上有详细的讨论;translation 可以直接利用这些信息
按我的经验,写大作业最重要的是不要怕,知道什么就写什么,写到最后写不出来了,你就知道问题所在了,比如可能有什么东西你还没学过
我基本都是写了一遍,然后再推倒重写的;在实际项目中第一次写的叫 prototype,第二次写的才是 production
关于type的问题
那些Type类只是一个例子,应该自己自己考虑设计自己的类,来使自己的编程尽量方便
Q:
wiki:http://acm.sjtu.edu.cn/wiki/Compiler_2014:_Types
Array类型是继承自Type类型的,我觉得应该是继承自Pointer类型比较好吧?
A:
Array behaves differently from Pointers in type checking. For example,
int *c = xxx; c = yyy; ... // changing where c points
is allowed, but
int c[] = {1,2,3}; c = ....
is not allowed.
Q:
Function类型里argumentType不是一个list,结合上面被划掉的一句话,我的理解是:类似LISP里用一元函数嵌套起来实现多元函数的方法,把argumentType这样套起来。
不过上面那句话说的是把returnType套起来,我不太理解。
这样做(而不用list)的好处是方便实现可变参数吗?
A:
This is called http://en.wikipedia.org/wiki/Currying
This design enables first-class functions, which is a bonus.
zero length array资料
官方的说明里面表示这是对于flexible array member的C99之前的写法,相比之下,zero length array的优势是这样定义出来的结构体是完整的,
可以在栈上或者静态分配空间,可以使用sizeof运算符,可以作为数组成员,可以出现在结构体的任何位置(这一条感觉不太靠谱)。
http://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
http://stackoverflow.com/questions/11733981/what-is-the-purpose-of-a-zero-length-array-in-a-struct
实现上可能需要注意的事情是,对于初始化列表要特殊处理,避免错误覆盖了紧跟其后的数据。
资料分享
有用的资料:
http://stackoverflow.com/questions/21275992/redeclaration-of-global-variable-vs-local-variable
这个是关于在全局声明和在局部声明语义上不同的解释。
http://eli.thegreenplace.net/2011/05/02/the-context-sensitivity-of-c’s-grammar-revisited/
https://en.wikipedia.org/wiki/The_lexer_hack
http://stackoverflow.com/questions/22904848/what-is-c-local-function-declaration-mechanism#22913970
有关typedef的实现
Q:
typedef int A; int main(){ A A; }
在里面两个A分别是外层的typedef name和内层的未声明的标识符。。。就是这种情况不太好处理
A:
在 action 里维护 scope 就可以了
例子 :
typedef int A; int main() { A }
gcc给的编译错误是缺少identifier
而
int main() { A }
给的编译错误是缺少类型
所以说其实就是lexer先去查一下table看看是不是有了记录(是id或是typename),没有的话就假定是id。
另外在parser分析语法吞下一个type specifier的时候,立马把状态强行切到id。再多考虑一下应该就没问题了。
cast 那部分还需要类似调整context
就是这个在得到一个type-specifier的时候强制变成id,在下面的代码可能会出现问题吧
typedef int A; int main(){ A a = (A)'a'; }
type-name 后面应该不能紧跟另一个 type-name
所以 lexer 吐出一个 type-name 之后,就不能紧跟着再吐一个 type-name
是吐出一个 typedef-name 之后不能连续再吐一个 typedef-name 只能吐成 identifier
A a 这里 a 必须是 identifier 因为刚刚已经吐了一个 typedef-name A 了
A a = (A 这里 A 可以是 typedef-name 因为刚刚吐的是左括号
嵌套struct定义
Q:
嵌套struct定义,内层的struct作用域为何算在file scope?
A:
因为规范中说 struct union enum 共用一个命名空间导致的吧
http://stackoverflow.com/questions/3793952/understanding-c-namespaces
同一个scope里可以有相同名字的属于不同namespace的东西的
gcc的一些问题
Q:
#include "stdio.h" int b,a=b; int main(){}
这样gcc是无法编译通过的
#include "stdio.h" int main() {int b,a=b;}
为何这样就能通过了呢?
A:
file scope初始化要求常量,而其他的不要求
C对于struct成员的限制的, struct 成员不能是函数类型
对jflex+cup用户可能有用的东西
在.cup文件里,变量名加上left是lexer里面生成token时的第一个整型参数,加right是第二个整型参数
比如.flex里构造token时
new java_cup.runtime.Symbol(type, yyline, yycolumn, value);
在.cup里一条语法规则
constant ::= INTEGER:i {: :};
ileft就是yyline,iright是yycolumn,这样就可以获取token的位置信息了
这个对生成编译信息应该有帮助
p.s. 应该有更简单的方法