Debian编译型语言代码详解

2024-11-09 3

在Debian系统中,编译型语言代码通常用于开发高性能的应用程序和系统工具。C语言是最常用的编译型语言之一,它提供了底层的硬件访问和高效的性能。本教程将介绍如何使用gcc编译器编写简单的C程序,以及使用Flex和Bison工具进行词法分析和语法分析。

编译相关软件包列表:

软件包流行度大小说明
gccV:166, I:55147GNU C 编译器
libc6-devV:259, I:56912051GNU C 库:开发库和头文件
g++V:53, I:50114GNU C++ 编译器
libstdc++-10-devV:15, I:17217537GNU 标准 C++ 库 版本 3(开发文件)
cppV:331, I:72730GNU C 预处理
gettextV:57, I:2595817GNU 国际化工具
gladeV:0, I:51209GTK 用户界面构建器
valacV:0, I:4724使用 GObject 系统类似 C# 的语言
flexV:7, I:741243LEX 兼容的 fast lexical analyzer generator
bisonV:7, I:803116YACC 兼容的 解析器生成器
susv2I:016通过“单一UNIX规范(版本2)”获取(英语文档)
susv3I:016通过“单一UNIX规范(版本3)”获取(英语文档)
susv4I:016通过“单一UNIX规范(版本4)”获取(英语文档)
golangI:2011Go 编程语言编译器
rustcV:3, I:148860Rust 系统编程语言
haskell-platformI:112标准的 Haskell 库和工具
gfortranV:6, I:6316GNU Fortran 95 编译器
fpcI:2103自由 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 解析器生成器列表:

软件包流行度大小说明
bisonV:7, I:803116GNU LALR 解析器生成器
byaccV:0, I:4258伯克利(Berkeley)LALR 解析器生成器
btyaccV:0, I:0243基于 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