识别龙书中过时的C代码
我目前正在阅读《编译器:原理、技术和工具》一书 我以前从未用C编写过代码(尽管我涉猎过C++),但从其他编程知识来看,大部分代码都是有意义的,不过我注意到一个怪癖,即函数的定义如下:识别龙书中过时的C代码,c,obsolete,C,Obsolete,我目前正在阅读《编译器:原理、技术和工具》一书 我以前从未用C编写过代码(尽管我涉猎过C++),但从其他编程知识来看,大部分代码都是有意义的,不过我注意到一个怪癖,即函数的定义如下: emit(t, tval) int t, tval { } 我发现有些地方不对劲,于是查了一下,果然,那种定义函数的方法似乎已经过时了。我希望有人能读懂我在下面重新键入的代码,并警告我任何不好的做法或过时的技术,否则我可能不会注意到并学会。此外,如果您能了解C语言的新特性,帮助我更简洁地编写代码,我将不胜
emit(t, tval)
int t, tval
{
}
我发现有些地方不对劲,于是查了一下,果然,那种定义函数的方法似乎已经过时了。我希望有人能读懂我在下面重新键入的代码,并警告我任何不好的做法或过时的技术,否则我可能不会注意到并学会。此外,如果您能了解C语言的新特性,帮助我更简洁地编写代码,我将不胜感激。我主要是寻找那些利用语义、特性、函数等不再在标准C规范中使用的代码,而不是从风格的角度
此外,如果你有一本书,不介意翻阅一下,看看(甚至从记忆中)你是否能发现其他过时或多余的做事方法,那也太棒了
我不确定这是否更适合CodeReview,如果是的话,请发表评论,我将删除并重新发布在那里,但我认为因为它来自一个流行的编程文本,所以它可能更适合这里。如果我错了,我会道歉
全球
#include <stdio.h>
#include <ctype.h>
#define BSIZE 128
#define NONE -1
#define EOS '\0'
#define NUM 256
#define DIV 257
#define MOD 258
#define ID 259
#define DONE 260
int tokenval;
int lineno;
struct entry {
char *lexptr;
int token;
};
struct entry symtable[];
解析器.c
#include "global.h"
int lookahead;
parse()
{
lookahead = lexan();
while (lookahead != DONE) {
expr(); match(';');
}
}
expr()
{
int t;
term();
while (1)
switch (lookahead) {
case '+': case '-':
t = lookahead;
match(lookahead); term(); emit(t, NONE);
continue;
default:
return;
}
}
term()
{
int t;
factor();
while (1)
switch (lookahead) {
case '*': case '/':
t = lookahead;
match(lookahead); factor(); emit(t, NONE);
continue;
default:
return;
}
}
factor()
{
switch (lookahead) {
case '(':
match('('); expr(); match(')'); break;
case NUM:
emit(NUM, tokenval); match(NUM); break;
case ID:
emit(ID, tokenval); match(ID); break;
default:
error("Syntax error");
}
}
match (t)
int t;
{
if (lookahead == t)
lookahead = lexan();
else error("Syntax error");
}
除了刚才提到的老式函数参数声明之外,我只浏览了一下代码,我看到的另一个过时的特性是在不返回任何内容的函数上缺少返回类型。例如,
parse
函数不返回任何内容,这段旧代码将其声明为parse()
,而现代代码需要void parse()
。还有一个问题是,不接受任何参数的函数的括号之间应该有void
(例如,void parse(void)
),但我认为这不是严格要求的。一些无序的东西:全局变量(tokenval、lineno…)的样式不正确
if (t == ' ' || t == '\t')
;
只有我的观点,但更具可读性:
if (t == ' ' || t == '\t') {}
有些函数调用可能会失败但是没有错误检查(至少scanf,可能更多) 这不应该编译,缺少
代码>
省略像parse()
这样的返回类型是非常糟糕的样式。
诸如此类
match (t)
int t;
应该是
match (int t)
(同样,也缺少返回类型)
也许我会因为愚蠢而被否决,但是:
动态大小的数组定义,如char-lexbuf[BSIZE]代码>…
有了所有不同的标准,我不知道哪里允许,哪里不允许,
但如果您想确保可以在任何地方编译它,
自己分配(指针、malloc、免费)Ah;谢谢我想我的大脑有点抽搐,在没有空白返回类型的情况下输入,但忽略了它。可能永远也不会意识到在括号中加上void也是一个好主意-谢谢:)BSIZE
是一个预处理器指令,在global.h
中定义为128,所以char-lexbuf[BSIZE]
应该适用于几乎所有版本的C,甚至是C99中引入可变数组之前的版本;是我打错了。很抱歉谢谢你的细心——非常有帮助。既然C语言中没有对象(至少据我所知),如果全局变量听起来不太无知,那么它的替代方案是什么?@AshleyDavies:将所有内容作为函数参数/返回值传递。这将更加复杂,但全球。变量有几个缺点。关于对象:没有类,但是可以使用结构将一些变量打包在一起。就像一个没有任何方法的类(或继承或…)
match (t)
int t;
match (int t)