在Debian系統(tǒng)中,編譯型語(yǔ)言代碼通常用于開發(fā)高性能的應(yīng)用程序和系統(tǒng)工具。C語(yǔ)言是最常用的編譯型語(yǔ)言之一,它提供了底層的硬件訪問和高效的性能。本教程將介紹如何使用gcc編譯器編寫簡(jiǎn)單的C程序,以及使用Flex和Bison工具進(jìn)行詞法分析和語(yǔ)法分析。
編譯相關(guān)軟件包列表:
軟件包 | 流行度 | 大小 | 說明 |
gcc | V:166, I:551 | 47 | GNU C 編譯器 |
libc6-dev | V:259, I:569 | 12051 | GNU C 庫(kù):開發(fā)庫(kù)和頭文件 |
g++ | V:53, I:501 | 14 | GNU C++ 編譯器 |
libstdc++-10-dev | V:15, I:172 | 17537 | GNU 標(biāo)準(zhǔn) C++ 庫(kù) 版本 3(開發(fā)文件) |
cpp | V:331, I:727 | 30 | GNU C 預(yù)處理 |
gettext | V:57, I:259 | 5817 | GNU 國(guó)際化工具 |
glade | V:0, I:5 | 1209 | GTK 用戶界面構(gòu)建器 |
valac | V:0, I:4 | 724 | 使用 GObject 系統(tǒng)類似 C# 的語(yǔ)言 |
flex | V:7, I:74 | 1243 | LEX 兼容的 fast lexical analyzer generator |
bison | V:7, I:80 | 3116 | YACC 兼容的 解析器生成器 |
susv2 | I:0 | 16 | 通過“單一UNIX規(guī)范(版本2)”獲取(英語(yǔ)文檔) |
susv3 | I:0 | 16 | 通過“單一UNIX規(guī)范(版本3)”獲?。ㄓ⒄Z(yǔ)文檔) |
susv4 | I:0 | 16 | 通過“單一UNIX規(guī)范(版本4)”獲取(英語(yǔ)文檔) |
golang | I:20 | 11 | Go 編程語(yǔ)言編譯器 |
rustc | V:3, I:14 | 8860 | Rust 系統(tǒng)編程語(yǔ)言 |
haskell-platform | I:1 | 12 | 標(biāo)準(zhǔn)的 Haskell 庫(kù)和工具 |
gfortran | V:6, I:63 | 16 | GNU Fortran 95 編譯器 |
fpc | I:2 | 103 | 自由 Pascal |
一、C
可以通過下列方法設(shè)置適當(dāng)?shù)沫h(huán)境來(lái)編譯使用 C 編程語(yǔ)言編寫的程序。
# apt-get install glibc-doc manpages-dev libc6-dev gcc build-essential
libc6-dev 軟件包,即 GNU C 庫(kù),提供了 C 標(biāo)準(zhǔn)庫(kù),它包含了 C 編程語(yǔ)言所使用的頭文件和庫(kù)例程。
參考信息如下:
- “info libc”(C 庫(kù)函數(shù)參考)
- gcc(1) 和 “info gcc”
- each_C_library_function_name(3)
- Kernighan & Ritchie,“C 程序設(shè)計(jì)語(yǔ)言”,第二版(Prentice Hall)
二、簡(jiǎn)單的C程序
一個(gè)簡(jiǎn)單的例子 “example.c” 可以通過如下方式和 “l(fā)ibm” 庫(kù)一起編譯為可執(zhí)行程序 “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” 鏈接來(lái)自 libc6 軟件包的庫(kù) “/usr/lib/libm.so”。實(shí)際的庫(kù)文件位于 “/lib/”,文件名為 “l(fā)ibm.so.6”,它是指向 “l(fā)ibm-2.7.so” 的一個(gè)鏈接。
請(qǐng)看一下輸出文本的最后一段。即使指定了 “%10s”,它依舊超出了 10 個(gè)字符。
使用沒有邊界檢查的指針內(nèi)存操作函數(shù),比如 sprintf(3) 和 strcpy(3), 是不建議使用,是為防止緩存溢出泄露而導(dǎo)致上面的溢出問題。請(qǐng)使用 snprintf(3) 和 strncpy(3) 來(lái)替代.
三、Flex
Flex 是兼容 Lex 的快速語(yǔ)法分析程序生成器??梢允褂?“info flex” 查看 flex(1) 的教程。
很多簡(jiǎn)單的例子能夠在 “/usr/share/doc/flex/examples/”下發(fā)現(xiàn)。[8]
四、Bison
在 Debian 里,有幾個(gè)軟件包提供 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()”.通常,F(xiàn)lex 創(chuàng)建的 “main()” 調(diào)用 “yyparse()”,它又調(diào)用了 “yylex()”.
創(chuàng)建 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); }
創(chuàng)建 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?*/?} %%
按下面的方法來(lái)從 shell 提示符執(zhí)行來(lái)嘗試這個(gè):
$ 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