在Debian系统中,编译型语言代码通常用于开发高性能的应用程序和系统工具。C语言是最常用的编译型语言之一,它提供了底层的硬件访问和高效的性能。本教程将介绍如何使用gcc编译器编写简单的C程序,以及使用Flex和Bison工具进行词法分析和语法分析。
编译相关软件包列表:
软件包 | 流行度 | 大小 | 说明 |
gcc | V:166, I:551 | 47 | GNU C 编译器 |
libc6-dev | V:259, I:569 | 12051 | GNU C 库:开发库和头文件 |
g++ | V:53, I:501 | 14 | GNU C++ 编译器 |
libstdc++-10-dev | V:15, I:172 | 17537 | GNU 标准 C++ 库 版本 3(开发文件) |
cpp | V:331, I:727 | 30 | GNU C 预处理 |
gettext | V:57, I:259 | 5817 | GNU 国际化工具 |
glade | V:0, I:5 | 1209 | GTK 用户界面构建器 |
valac | V:0, I:4 | 724 | 使用 GObject 系统类似 C# 的语言 |
flex | V:7, I:74 | 1243 | LEX 兼容的 fast lexical analyzer generator |
bison | V:7, I:80 | 3116 | YACC 兼容的 解析器生成器 |
susv2 | I:0 | 16 | 通过“单一UNIX规范(版本2)”获取(英语文档) |
susv3 | I:0 | 16 | 通过“单一UNIX规范(版本3)”获取(英语文档) |
susv4 | I:0 | 16 | 通过“单一UNIX规范(版本4)”获取(英语文档) |
golang | I:20 | 11 | Go 编程语言编译器 |
rustc | V:3, I:14 | 8860 | Rust 系统编程语言 |
haskell-platform | I:1 | 12 | 标准的 Haskell 库和工具 |
gfortran | V:6, I:63 | 16 | GNU Fortran 95 编译器 |
fpc | I:2 | 103 | 自由 Pascal |
一、C
可以通过下列方法设置适当的环境来编译使用 C 编程语言编写的程序。
# apt-get install glibc-doc manpages-dev libc6-dev gcc build-essential
libc6-dev 软件包,即 GNU C 库,提供了 C 标准库,它包含了 C 编程语言所使用的头文件和库例程。
参考信息如下:
- “info libc”(C 库函数参考)
- gcc(1) 和 “info gcc”
- each_C_library_function_name(3)
- Kernighan & Ritchie,“C 程序设计语言”,第二版(Prentice Hall)
二、简单的C程序
一个简单的例子 “example.c” 可以通过如下方式和 “libm” 库一起编译为可执行程序 “run_example”。
<a id="_simple_c_program_gcc"><pre class="screen">$ cat > example.c << EOF #include <stdio.h> #include <math.h> #include <string.h> int main(int argc, char **argv, char **envp){ double x; char y[11]; x=sqrt(argc+7.5); strncpy(y, argv[0], 10); /* prevent buffer overflow */ y[10] = '\0'; /* fill to make sure string ends with '\0' */ printf("%5i, %5.3f, %10s, %10s\n", argc, x, y, argv[1]); return 0; } EOF $ gcc -Wall -g -o run_example example.c -lm $ ./run_example 1, 2.915, ./run_exam, (null) $ ./run_example 1234567890qwerty 2, 3.082, ./run_exam, 1234567890qwerty
为了使用 sqrt(3),必须使用 “-lm” 链接来自 libc6 软件包的库 “/usr/lib/libm.so”。实际的库文件位于 “/lib/”,文件名为 “libm.so.6”,它是指向 “libm-2.7.so” 的一个链接。
请看一下输出文本的最后一段。即使指定了 “%10s”,它依旧超出了 10 个字符。
使用没有边界检查的指针内存操作函数,比如 sprintf(3) 和 strcpy(3), 是不建议使用,是为防止缓存溢出泄露而导致上面的溢出问题。请使用 snprintf(3) 和 strncpy(3) 来替代.
三、Flex
Flex 是兼容 Lex 的快速语法分析程序生成器。可以使用 “info flex” 查看 flex(1) 的教程。
很多简单的例子能够在 “/usr/share/doc/flex/examples/”下发现。[8]
四、Bison
在 Debian 里,有几个软件包提供 Yacc兼容的前瞻性的 LR 解析 或 LALR 解析的生成器。
兼容 Yacc 的 LALR 解析器生成器列表:
软件包 | 流行度 | 大小 | 说明 |
---|---|---|---|
bison |
V:7, I:80 | 3116 | GNU LALR 解析器生成器 |
byacc |
V:0, I:4 | 258 | 伯克利(Berkeley)LALR 解析器生成器 |
btyacc |
V:0, I:0 | 243 | 基于 byacc 的回溯解析生成器 |
可以使用 “info bison” 查看 bison(1) 的教程。需要提供自己的的 “main()” 和 “yyerror()”.通常,Flex 创建的 “main()” 调用 “yyparse()”,它又调用了 “yylex()”.
创建 example.y:
/* calculator source for bison */ %{ #include <stdio.h> extern int yylex(void); extern int yyerror(char *); %} /* declare tokens */ %token NUMBER %token OP_ADD OP_SUB OP_MUL OP_RGT OP_LFT OP_EQU %% calc: | calc exp OP_EQU { printf("Y: RESULT = %d\n", $2); } ; exp: factor | exp OP_ADD factor { $$ = $1 + $3; } | exp OP_SUB factor { $$ = $1 - $3; } ; factor: term | factor OP_MUL term { $$ = $1 * $3; } ; term: NUMBER | OP_LFT exp OP_RGT { $$ = $2; } ; %% int main(int argc, char **argv) { yyparse(); } int yyerror(char *s) { fprintf(stderr, "error: '%s'\n", s); }
创建 example.l:
/* calculator source for flex */ %{ #include "example.tab.h" %} %% [0-9]+ { printf("L: NUMBER = %s\n", yytext); yylval = atoi(yytext); return NUMBER; } "+" { printf("L: OP_ADD\n"); return OP_ADD; } "-" { printf("L: OP_SUB\n"); return OP_SUB; } "*" { printf("L: OP_MUL\n"); return OP_MUL; } "(" { printf("L: OP_LFT\n"); return OP_LFT; } ")" { printf("L: OP_RGT\n"); return OP_RGT; } "=" { printf("L: OP_EQU\n"); return OP_EQU; } "exit" { printf("L: exit\n"); return YYEOF; } /* YYEOF = 0 */ . { /* ignore all other */ } %%
按下面的方法来从 shell 提示符执行来尝试这个:
$ bison -d example.y $ flex example.l $ gcc -lfl example.tab.c lex.yy.c -o example $ ./example $ ./example 1 + 2 * ( 3 + 1 ) = L: NUMBER = 1 L: OP_ADD L: NUMBER = 2 L: OP_MUL L: OP_LFT L: NUMBER = 3 L: OP_ADD L: NUMBER = 1 L: OP_RGT L: OP_EQU Y: RESULT = 9 exit L: exit