c模板編程pdf
『壹』 C中實現模板
模版的功能,不能用c語言實現的!
這種功能,需要編譯器的支持。
如果你不是想重載的話,倒是可以實現的。
你最好把問題再簡化一下,我覺得我還不太理解你的意思。
『貳』 C中的模板怎樣使用 最好給個例子~
看看這個吧
http://www.njcc.e.cn/njhysite/njhygao_js/xuebao/xuebao0402/zhjm.doc
其他的見
C語言中實現模板函數的方法
在C語言中實現模板函數的方法:
各種用C語言實現的模板可能在使用形式上有所不同。
現以一個求和函數Sum為例,用C++Template可寫如下:
template<classT,classR> RSum(constT*array,intn)
{
Rsum=0;
for(inti=0;i<n;++i)
sum+=i;
returnsum;
}
如果不是內置類型,該模板隱式地需要有RR::operator+=(T)運算符可用。
1. 使用函數指針作為Functor替換者
TypedefstructtagAddClass
{
Void(*add)(char*r1,constchar*r2);
IntelemSize;
Char sum[MAX_ELEM_SIZE];
}AddClass;
voidSum(AddClass*self,constchar*array,intn)
{
for(inti=0;i<n;++i)
self->add(self->sum,array+i*self->elemSize);
}
使用時:
…..
VoidAddInt(char*r1,constchar*r2)
{
*(long*)r1+=*(int*)r2;
}
AddClassaddClass={AddInt,2,0};
Intarray[100];
Read(array);
Sum(&addClass,array,100);
…..
2. 用宏作為Functor的替換者
#define GenSumFun(SumFunName,Add,RetType,ElemType) \
RetTypeSumFunName(constElemType*array,intn) \
{ \
RetTypesum=0; \
for(inti=0;i<n;++i) \
Add(sum,i); \
returnsum; \
}
使用時:
#defineAddInt(x,y) ((x)+=(y))
GenSumFun(SumInt,AddInt,long,int)
…..
Intarray[100];
Read(array);
Longsum=SumInt(array,100);
…..
3. 所有可替換參數均為宏
至少需要一個額外的文件(實現文件)為impsum.c
/*impsum.c*/
RetTypeFunName(constElemType*array,intn)
{
RetTypesum=0;
for(inti=0;i<n;++i)
Add(sum,i);
returnsum;
}
使用時:
#undef RetType
#undef FunName
#undef ElemType
#undef Add
#defineAddInt(x,y) ((x)+=(y))
#defineRetTypelong
#defineFunNameSumInt
#defineElemTypeint
#defineAdd AddInt
#includeimpsum.c
…..
Intarray[100];
Read(array);
Longsum=SumInt(array,100);
…..
4. 總結:
第一種方法,易於跟蹤調試,但是效率低下,適用於對可變函數(函數指針)的效率要求不高,但程序出錯的可能性較大(復雜),模板函數(Sum)本身很復雜,模板參數也比較復雜(add)的場合。
第二種方法,效率高,但很難跟蹤調試,在模板函數和模板參數本身都很復雜的時候更是如此。
第三種方法,是我最近幾天才想出的,我認為是最好的,在模板參數(Add)比較復雜時可以用函數(第二種也可以如此),簡單時可以用宏,並且,易於調試。在模板函數本身很復雜,而模板參數比較簡單時更為優越。但是,可能有點繁瑣。
一般情況下,沒有必要做如此勞心的工作,一切交給編譯器去做就行了。但是本人在開發一個文件系統時,由於是基於一種少見的平台,沒有可用的C++編譯器,有幾個函數,除了其中的類型不同(uint16和uint32),和幾個可參數化的宏不同,其它地方完全相同,而函數本身很復雜(兩百多行代碼)。Copy出幾個完全類似的函數副本,維護起來特別煩人。非常需要如此的編程模式,故此,分享出來,大家共同探討。
『叄』 求一本《c專家編程》pdf非掃描版
鏈接: https://pan..com/s/1vvTsBaWnbv_dS8AdDoj_LQ
『肆』 c語言編程在線急(用標簽里的代碼模板)
#include"stdio.h"
voidoutput(inta[],intn);
main()
{
intn,i,j,x,pos;
intc=0;//c表示有效的數據個數
inta[20];
scanf("%d",&n);
for(i=0;i<n;i++)//插入n個數據
{
scanf("%d",&x);
//查找插入的位置pos,並且向後移動數據
for(pos=c;pos>0;pos--)
if(x<a[pos-1])
a[pos]=a[pos-1];
else
break;
a[pos]=x;//在pos位置插入數據
c++;//個數加1
}
output(a,n);
return0;
}
voidoutput(inta[],intn)
{
inti;
for(i=0;i<n;i++)
printf("%d",a[i]);
printf(" ");
}
『伍』 在c語言中如何實現函數模板
如果要寫個函數支持多種數據類型,首先想到的就是C++的模板了,但是有時候只能用C語言,比如在linux內核開發中,為了減少代碼量,或者是某面試官的要求…
考慮了一陣子後,就想到了qsort上.qsort的函數原型:
void qsort( void *base, size_t num, size_t width, int (__cdecl *compare )(const void *elem1, const void *elem2 ) );
快排時,只要自己實現相應數據類型的比較函數cmpare就可以了.如果比較int型時,一個典型的compare函數如下:
那麼,就是說可以利用void *. void *意指未指定類型,也可以理解為任意類型。其他類型的指針可以直接賦值給void *變數,但是void *變數需要強制類型轉換為其它指針類型。這個相信大家都知道。那麼下面以一個簡單的題目為例,來探討如何在C語言中實現模板函數。
方法1: 利用void *.
在看下面的源程序之前,需要了解幾點。首先,在32位平台上,任何類型的指針所佔的位元組都是4個位元組,因為32位機器虛擬內存一般為4G,即2的32次方,只要32位即4個位元組就可以足夠定址,sizeof(void *)=4; 其次,雖然各種不同類型的指針所佔的空間都為4個位元組,但是不同類型的指針所指的空間的位元組數卻不同(這一點尤為重要,下面的程序我在開始沒有調通就因為這點意識不強)。所以,如果你將一個指針強制轉換為另一個類型的指針,指針本身所佔的位元組是不變的,但是,如果對這個指針進行運算,比如 *p,p++,p-=1等一般都是不同的。 再次,函數指針應該了解下,這里不多說。 最後,因為Sandy跟我說,C++開始的時候模板的實現其實就是利用宏替換,在編譯的時候確定類型。所以,為了方便,類型也用了預編譯指令#define。
<span>#include"stdio.h"</span>
<span>#include"stdlib.h"</span>
<span>//typedefintT;//或者下面的也可以.</span>
<span>#defineTint</span>
//這個FindMin是Sandy寫的.felix021也寫了個,差不多的就不貼出來的.
voidFindMin(constvoid*arr,intarr_size,intarrmembersize,int*index,
int(*cmp)(constvoid*,constvoid*b)){
inti;
*index=0;
char*p=(char*)arr;
char*tmp=p;
for(i=1;i<arr_size;i++){
if(cmp(tmp,p)>0){
tmp=p;
}
p+=arrmembersize;
}
(*index)=((int)(tmp-arr))/arrmembersize;
}
*/</span>
可以把指針看作是char*,如果轉換為int*,那下面的位移就不正確了.</span>
index<span>=</span>i<span>;</span>
<span>}</span>
<span>}</span>
<span>return</span>index<span>;</span>
<span>}</span>
<span>int</span>result<span>;</span><span>//result保存的是最小值索引.</span>
result<span>=</span>FindMin<span>(</span>arr,<span>12</span>,
『陸』 c語言課程設計報告模板
課程設計報告內容
報告應包括以下內容:
摘要(300~400字)
目錄
1. 概述
2. 課程設計任務及要求
2.1 設計任務
2.2 設計要求
3. 理論設計
3.1方案論證
3.2 系統設計
3.2.1 結構框圖及說明
3.2.2 系統原理圖及工作原理
3.3 單元電路設計
3.3.1單元電路工作原理
3.3.2元件參數選擇
4. 系統設計
4.1 軟體設計
4.2 編程過程
4.2 編程結果
5. 安裝調試
5.2 安裝調試過程
5.3 故障分析
6. 結論
7. 使用儀器設備清單
8. 收獲、體會和建議
9. 參考文獻
『柒』 求C語言pdf格式的幾本書!!!
這幾本在網上都可以找到的,C語言我建議你看的就是 K&R C程序設計,另一本要看的ANSI C標准,其它的都是浮雲。。unix編程和系統編程 ,這兩本太大了。。但是在網上都可以搜索到。。去google unix系統編程 filetype:pdf會搜索到的。。切記C和指針是拉圾 C缺陷和缺陷拉圾 C專家編程拉圾。。 我是過來人。。特別是ANSI C 標准 (在CSDN有下載 包括C++2011的標准) 看標准才是王道。另外就是你要多去悟,不要限於那些無用的技巧呀, 語法呀。。真的。。C語言學好了。。基本說你在編程語言這塊沒有問題了,剩下的就是主攻演算法,啥MFC 啥reactos 都是浮雲,看來樓主是喜歡linux,學linux去csdn下一下常規命令的源碼,分析一下linux的源碼你會大有長進。。
『捌』 求《LINUXC編程一站式學習》全文免費下載百度網盤資源,謝謝~
《LINUX C編程一站式學習》網路網盤pdf最新全集下載:
鏈接:https://pan..com/s/1wIgN0sfCc9gjkgPdARtUng
簡介:通俗易懂的原理剖析,有非常適合初學者的code,有形象化的展示。本書分為兩部分:第一部分講解編程語言和程序設計的基本思想方法,讓讀者從概念上認識C語言。
『玖』 吐血整理:C++編程語言資源匯總
關於 C++ 框架、庫和資源的一些匯總列表,內容包括:標准庫、Web應用框架、人工智慧、資料庫、圖片處理、機器學習、日誌、代碼分析等。有需要的小夥伴可以收藏一下!
C++標准庫,包括了STL容器,演算法和函數等。
C++ Standard Library:是一系列類和函數的集合,使用核心語言編寫,也是C++ISO自身標準的一部分。
Standard Template Library:標准模板庫
C POSIX library : POSIX系統的C標准庫規范
ISO C++ Standards Committee :C++標准委員會
C++通用框架和庫
Apache C++ Standard Library:是一系列演算法,容器,迭代器和其他基本組件的集合
ASL :Adobe源代碼庫提供了同行的評審和可移植的C++源代碼庫。
Boost :大量通用C++庫的集合。
BDE :來自於彭博資訊實驗室的開發環境。
Cinder:提供專業品質創造性編碼的開源開發社區。
Cxxomfort:輕量級的,只包含頭文件的庫,將C++ 11的一些新特性移植到C++03中。
Dlib:使用契約式編程和現代C++ 科技 設計的通用的跨平台的C++庫。
EASTL :EA-STL公共部分
ffead-cpp :企業應用程序開發框架
Folly:由Facebook開發和使用的開源C++庫
JUCE :包羅萬象的C++類庫,用於開發跨平台軟體
libPhenom:用於構建高性能和高度可擴展性系統的事件框架。
LibSourcey :用於實時的視頻流和高性能網路應用程序的C++11 evented IO
LibU : C語言寫的多平台工具庫
Loki :C++庫的設計,包括常見的設計模式和習語的實現。
MiLi :只含頭文件的小型C++庫
openFrameworks :開發C++工具包,用於創意性編碼。
Qt :跨平台的應用程序和用戶界面框架
Reason :跨平台的框架,使開發者能夠更容易地使用Java,.Net和Python,同時也滿足了他們對C++性能和優勢的需求。
ROOT :具備所有功能的一系列面向對象的框架,能夠非常高效地處理和分析大量的數據,為歐洲原子能研究機構所用。
STLport:是STL具有代表性的版本
STXXL:用於額外的大型數據集的標准模板庫。
Ultimate++ :C++跨平台快速應用程序開發框架
Windows Template Library:用於開發Windows應用程序和UI組件的C++庫
Yomm11 :C++11的開放multi-methods.
btsk : 游戲 行為樹啟動器工具
Evolving Objects:基於模板的,ANSI C++演化計算庫,能夠幫助你非常快速地編寫出自己的隨機優化演算法。
Neu:C++11框架,編程語言集,用於創建人工智慧應用程序的多用途軟體系統。
Boost.Asio:用於網路和底層I/O編程的跨平台的C++庫。
libev :功能齊全,高性能的時間循環,輕微地仿效libevent,但是不再像libevent一樣有局限性,也修復了它的一些bug。
libevent :事件通知庫
libuv :跨平台非同步I/O。
音頻,聲音,音樂,數字化音樂庫
FMOD :易於使用的跨平台的音頻引擎和音頻內容的 游戲 創作工具。
Maximilian :C++音頻和音樂數字信號處理庫
OpenAL :開源音頻庫—跨平台的音頻API
Opus:一個完全開放的,免版稅的,高度通用的音頻編解碼器
Speex:免費編解碼器,為Opus所廢棄
Tonic: C++易用和高效的音頻合成
Vorbis: Ogg Vorbis是一種完全開放的,非專有的,免版稅的通用壓縮音頻格式。
生物信息,基因組學和生物技術
libsequence:用於表示和分析群體遺傳學數據的C++庫。
SeqAn:專注於生物數據序列分析的演算法和數據結構。
Vcflib :用於解析和處理VCF文件的C++庫
Wham:直接把聯想測試應用到BAM文件的基因結構變異。
壓縮和歸檔庫
bzip2:一個完全免費,免費專利和高質量的數據壓縮
doboz:能夠快速解壓縮的壓縮庫
PhysicsFS:對各種歸檔提供抽象訪問的庫,主要用於視頻 游戲 ,設計靈感部分來自於Quake3的文件子系統。
KArchive:用於創建,讀寫和操作文件檔案(例如zip和 tar)的庫,它通過QIODevice的一系列子類,使用gzip格式,提供了透明的壓縮和解壓縮的數據。
LZ4 :非常快速的壓縮演算法
LZHAM :無損壓縮資料庫,壓縮比率跟LZMA接近,但是解壓縮速度卻要快得多。
LZMA :7z格式默認和通用的壓縮方法。
LZMAT :及其快速的實時無損數據壓縮庫
miniz:單一的C源文件,緊縮/膨脹壓縮庫,使用zlib兼容API,ZIP歸檔讀寫,PNG寫方式。
Minizip:Zlib最新bug修復,支持PKWARE磁碟跨越,AES加密和IO緩沖。
Snappy :快速壓縮和解壓縮
ZLib :非常緊湊的數據流壓縮庫
ZZIPlib:提供ZIP歸檔的讀許可權。
並發執行和多線程
Boost.Compute :用於OpenCL的C++GPU計算庫
Bolt :針對GPU進行優化的C++模板庫
C++React :用於C++11的反應性編程庫
Intel TBB :Intel線程構件塊
Libclsph:基於OpenCL的GPU加速SPH流體模擬庫
OpenCL :並行編程的異構系統的開放標准
OpenMP:OpenMP API
Thrust :類似於C++標准模板庫的並行演算法庫
HPX :用於任何規模的並行和分布式應用程序的通用C++運行時系統
VexCL :用於OpenCL/CUDA 的C++向量表達式模板庫。
C++ B-tree :基於B樹數據結構,實現命令內存容器的模板庫
Hashmaps: C++中開放定址哈希表演算法的實現
Bcrypt :一個跨平台的文件加密工具,加密文件可以移植到所有可支持的操作系統和處理器中。
BeeCrypt:
Botan: C++加密庫
Crypto++:一個有關加密方案的免費的C++庫
GnuPG: OpenPGP標準的完整實現
GnuTLS :實現了SSL,TLS和DTLS協議的安全通信庫
Libgcrypt
libmcrypt
LibreSSL:免費的SSL/TLS協議,屬於2014 OpenSSL的一個分支
LibTomCrypt:一個非常全面的,模塊化的,可移植的加密工具
libsodium:基於NaCI的加密庫,固執己見,容易使用
Nettle 底層的加密庫
OpenSSL : 一個強大的,商用的,功能齊全的,開放源代碼的加密庫。
Tiny AES128 in C :用C實現的一個小巧,可移植的實現了AES128ESB的加密演算法
資料庫,SQL伺服器,ODBC驅動程序和工具
hiberlite :用於Sqlite3的C++對象關系映射
Hiredis: 用於Redis資料庫的很簡單的C客戶端庫
LevelDB: 快速鍵值存儲庫
LMDB:符合資料庫四大基本元素的嵌入鍵值存儲
MySQL++:封裝了MySql的C API的C++ 包裝器
RocksDB:來自Facebook的嵌入鍵值的快速存儲
SQLite:一個完全嵌入式的,功能齊全的關系資料庫,只有幾百KB,可以正確包含到你的項目中。
調試庫, 內存和資源泄露檢測,單元測試
Boost.Test:Boost測試庫
Catch:一個很 時尚 的,C++原生的框架,只包含頭文件,用於單元測試,測試驅動開發和行為驅動開發。
CppUnit:由JUnit移植過來的C++測試框架
CTest:CMake測試驅動程序
googletest:谷歌C++測試框架
ig-debugheap:用於跟蹤內存錯誤的多平台調試堆
libtap:用C語言編寫測試
MemTrack —用於C++跟蹤內存分配
microprofile- 跨平台的網路試圖分析器
minUnit :使用C寫的迷你單元測試框架,只使用了兩個宏
Remotery:用於web視圖的單一C文件分析器
UnitTest++:輕量級的C++單元測試框架
Cocos2d-x :一個跨平台框架,用於構建2D 游戲 ,互動圖書,演示和其他圖形應用程序。
Grit :社區項目,用於構建一個免費的 游戲 引擎,實現開放的世界3D 游戲 。
Irrlicht :C++語言編寫的開源高性能的實時#D引擎
Polycode:C++實現的用於創建 游戲 的開源框架(與Lua綁定)。
CEGUI : 很靈活的跨平台GUI庫
FLTK :快速,輕量級的跨平台的C++GUI工具包。
GTK+: 用於創建圖形用戶界面的跨平台工具包
gtkmm :用於受歡迎的GUI庫GTK+的官方C++介面。
imgui:擁有最小依賴關系的立即模式圖形用戶界面
libRocket :libRocket 是一個C++ HTML/CSS 游戲 介面中間件
MyGUI :快速,靈活,簡單的GUI
Ncurses:終端用戶界面
QCustomPlot :沒有更多依賴關系的Qt繪圖控制項
Qwt :用戶與技術應用的Qt 控制項
QwtPlot3D :功能豐富的基於Qt/OpenGL的C++編程庫,本質上提供了一群3D控制項
OtterUI :OtterUI 是用於嵌入式系統和互動 娛樂 軟體的用戶界面開發解決方案
PDCurses 包含源代碼和預編譯庫的公共圖形函數庫
wxWidgets C++庫,允許開發人員使用一個代碼庫可以為widows, Mac OS X,Linux和其他平台創建應用程序
bgfx:跨平台的渲染庫
Cairo:支持多種輸出設備的2D圖形庫
Horde3D 一個小型的3D渲染和動畫引擎
magnum C++11和OpenGL 2D/3D 圖形引擎
Ogre 3D 用C++編寫的一個面向場景,實時,靈活的3D渲染引擎(並非 游戲 引擎)
OpenSceneGraph 具有高性能的開源3D圖形工具包
Panda3D 用於3D渲染和 游戲 開發的框架,用Python和C++編寫。
Skia 用於繪制文字,圖形和圖像的完整的2D圖形庫
urho3d 跨平台的渲染和 游戲 引擎。
Boost.GIL:通用圖像庫
CImg :用於圖像處理的小型開源C++工具包
CxImage :用於載入,保存,顯示和轉換的圖像處理和轉換庫,可以處理的圖片格式包括 BMP, JPEG, GIF, PNG, TIFF, MNG, ICO, PCX, TGA, WMF, WBMP, JBG, J2K。
FreeImage :開源庫,支持現在多媒體應用所需的通用圖片格式和其他格式。
GDCM:Grassroots DICOM 庫
ITK:跨平台的開源圖像分析系統
Magick++:ImageMagick程序的C++介面
MagickWnd:ImageMagick程序的C++介面
OpenCV : 開源計算機視覺類庫
tesseract-ocr:OCR引擎
VIGRA :用於圖像分析通用C++計算機視覺庫
VTK :用於3D計算機圖形學,圖像處理和可視化的開源免費軟體系統。
最後, 對於學習編程或者在工作想升職的程序員兄弟,如果你想更好的提升你的編程能力幫助你提升水平! 筆者這里或許可以幫到你~
編程學習書籍分享:
編程學習視頻分享:
分享(源碼、項目實戰視頻、項目筆記,基礎入門教程)
歡迎轉行和學習編程的夥伴,利用更多的資料學習成長比自己琢磨更快哦!
『拾』 c語言編程
//計劃做的腳本引擎的一部分
//參考的 C++編程藝術
//總地來說會有一些難度
//我的是C++應該會給你一些啟發
//TypeDef.h
#include "windows.h"
#ifndef B_TYPE_DEF_H
#define B_TYPE_DEF_H
const int MAX_T_LEN = 128;//可以分析的最大符號長度(同時決定了一個字元變數的最大長度為128位元組)
const int MAX_ID_LEN = 31;//允許的最大的標識長度(一個標識符是指一個變數名或函數名)
const int MAX_BUF_LEN = 1024;//解釋緩沖區1024位元組
const int NUM_PARAMS = 32;//最大參數數目
const int MAX_DIM_NUM = 65536//數組最大維數
//需要分析的所有東西
enum Token_Item { UNDEF=1, //未定義
E_TEMP,//當模板使用
E_CHAR,//char關鍵字
E_INT,//int關鍵字
E_FLOAT,//float關鍵字
E_SWITCH,//switch關鍵字
E_CASE,//case關鍵字
E_IF,//if關鍵字
E_ELSE,//else關鍵字
E_FOR,//for關鍵字
E_DO,//do關鍵字
E_WHILE,//while關鍵字
E_BREAK,//break關鍵字
E_RETURN,//return關鍵字
E_COUT,//cout關鍵字
E_CIN,//cin關鍵字
LBLOCK, //{
RBLOCK,//}
DOU,//,
EOS,//;
MAO,//:
SFEN,//'已舍棄,不含'分析
LT,//<
LE,//<=
GT,//>
GE,//>=
EQ,//==
NE,//!=
FF,//.
LK,//(
NOT,//!
INC,//++
DEC,//--
ADD,//+
SUB,//-
RK,//)
LZK,//[
RZK,//]
LS,//<<
RS,//>>
ASS,//=
AND,//&&
OR,//||
MUL,//*
DIV,///
MOD,//%
POW,//^
NUMBER, //數字
IDENTIFIER,//標識
STRING,//字元串
END//文件結束
};//需要分析的全部符號
enum Token_Type{
UNK,//未知類型
KEY,//關鍵字
FJF,//分界符
CMP,//比較運算符
OPE,//運算符
NUM,//數字
IDE,//標識符
STR,//字元串
NON,//結束符號
UDF//未定義
};
typedef struct Token_Table{//符號表
char name[MAX_T_LEN];
Token_Item token;
Token_Type type;
} TOKEN_TABLE,*PTOKEN_TABLE;
enum error_msg //錯誤類型
{ SYNTAX=1000, NO_EXP, NOT_VAR, DUP_VAR, DUP_FUNC,
SEMI_EXPECTED, UNBAL_BRACES, FUNC_UNDEF,
TYPE_EXPECTED, RET_NOCALL, PAREN_EXPECTED,
WHILE_EXPECTED, QUOTE_EXPECTED, DIV_BY_ZERO,
BRACE_EXPECTED, COLON_EXPECTED,FAIL_OPEN,ERROR_SIZE,
NO_MAIN,ERROR_ASSIGN,ERROR_RZK,ERROR_DIM};
class InterpExc { //錯誤類
error_msg err;
public:
InterpExc(error_msg e) { err = e; }
error_msg get_err() { return err; }
};
enum Vars{類型
V_Int,
V_Float,
V_String,
V_pInt,
V_pFloat,
V_pString,
V_Udef
};
#endif
#ifndef V_NULL
#define V_NULL (-1)
#endif
//Cfenxi.h
#include "TypeDef.h"
#include <iostream>
#include <vector>
#include <stack>
#include <algorithm>
#include <string>
using namespace std;
//Fenxi類說明
//curr_pt始終指向將要分析的地址
//prev_pt為前一個分析的地址
//可以使用函數GotoPt來改變當前分析地址
//分析結果放在變數stoken,item,type
//在Cfenxi.cpp中定義了一個文件級變數TOKEN_TABLE tokentable[];
//在使用的時候必須聲明這個變數
#ifndef B_CFENXI_H
#define B_CFENXI_H
class Fenxi{
public:
char stoken[MAX_T_LEN+1];//分析出來的符號名
char buff[MAX_BUF_LEN+1];//緩沖區
Token_Item item;//分析出來的具體符號
Token_Type type;//符號大類
long curr_pt;//當前分析點
long prev_pt;//前一個分析點
char pFileName[256];//腳本文件名
PTOKEN_TABLE pTokenTable;//符號表
public:
Fenxi(){};
~Fenxi(){};
void Create(char*,PTOKEN_TABLE,int);//創建分析對象
void GetToken();//分析一步
void GotoPt(long);//跳分析點
void PutBack();//回退一個分析點
private:
int nTableItem;//分析表中的分析數目
long iFileLength;//腳本文件長度
int iBlock;//當前所在區塊
int iYouBiao;//當前游標
char cbuff;//當前所指向的字元
char cbuff1;//超前搜索的字元
void MoveNext();//向下移動
void MovePrev();//向前移動
void LoadBlock();//裝入一個塊
long GetPt(int i,int n){return (long)(i*MAX_BUF_LEN+n);};//計算位置
bool KeyLookUp(char*,Token_Item &);//查找是不是關鍵詞
bool isdelim(char);
};
//解釋類
class var_value{
public:
char string_value[MAX_T_LEN+1];
int int_value;
float float_value;
Vars v_type;
public:
var_value()
{
int_value=0;
float_value=0;
string_value[0]=0;
v_type=Udef;
}
var_value(const var_value&);
set_type(Vars type){v_type=type;}
~var_value(){}
friend bool operator == (const var_value& _X, const var_value& _Y);
friend bool operator < (const var_value& _X, const var_value& _Y);
};
class temp_var_value{
public:
char string_value[MAX_T_LEN+1];
int int_value;
float float_value;
int p_int;
int p_float;
int p_string;
vector<int> dim;
Vars v_type;
public:
temp_var_value()
{
int_value=0;
float_value=0;
string_value[0]=0;
p_int=p_float=p_string=V_NULL;
v_type=Udef;
};
temp_var_value(const temp_var_value&);
temp_set_type(Vars type){v_type=type;}
~temp_var_value(){}
friend bool operator == (const temp_var_value& _X, const temp_var_value& _Y);
friend bool operator < (const temp_var_value& _X, const temp_var_value& _Y);
};
struct var_type { //變數類型
char var_name[MAX_ID_LEN+1]; // 變數名
Vars v_type;//數據類型
vector<var_value> value; //變數值
vector<int> v_dim;//變數維數
int v_max;//變數的最大數目
};
struct func_type {
char func_name[MAX_ID_LEN+1]; //函數名
Vars ret_type; //返回值類型
long loc; // 函數入口點,函數的入口點是指分析點指向函數括弧後第一個字元
};
class Script{
public:
Fenxi theFx;//詞法分析對象,負責對腳本文件的操作
char FileName[256];//腳本文件名
var_value ret_value;//返回值
bool breakfound;//中斷
public:
Script(){};
~Script(){};
void Create(char*,PTOKEN_TABLE,int);//創建腳本對象
void ExecuteScript();//開始解釋腳本
private:
void PreScan();//預掃描
void decl_global();//聲明全局變數
long find_func(char*);//返回函數的入口點
void ItemToVar(Token_Item,Vars&);//根據一個項,得到相當的變數類型
void CallFun();//執行一個函數
void get_args();//得到函數的形式參數名
void Interp();//具體解釋
private:
void eval_exp (var_value &value);
void eval_exp0(var_value &value);
void eval_exp1(var_value &value);
void eval_exp2(var_value &value);
void eval_exp3(var_value &value);
void eval_exp4(var_value &value);
void eval_exp5(var_value &value);
void eval_exp6(var_value &value);
void eval_exp7(var_value &value);
void eval_exp8(var_value &value);
bool is_var(char *s);
// 變數名,變數的維數,變數的值,變數的類型
void assign_var(char *var_name,int idx, var_value value);
void find_var_value(char *var_name,int idx,var_value& value);
int find_idx(vector<int>,vector<int>);// 計算[][]
void find_vector(vector<int> &);//讀取[]
int cal_idx(vector<int>);
Vars is_var_type;//使用is_var的時候如果返回值是真那麼這個變數存儲了變數類型
public:
//每執行一個函數的時候就把進入前的局部變數數目
//放到函數結點棧,函數執行完的時候就根據棧里的
//數據改變局部函數表裡的變數,從而實現變數的靈活使用
//同理塊結點棧的原理也一樣
//變數表
vector<var_type> global_vars; //全局變數表
vector<var_type> local_var_stack; //局部變數表(函數參數作為局部變數處理)
vector<func_type> func_table; //函數表
stack<int> func_call_stack;//函數結點棧
stack<int> nest_scope_stack;//塊結點棧
};
#endif
//Fenxi.cpp
#include "CFenxi.h"
#include <cstring>
#include <cctype>
#include <fstream>
#include <cstdio>
#include <cmath>
using namespace std;
///////////////////////////////////////////////////////////////////////
/////////////////////////詞法分析類的函數定義//////////////////////////
///////////////////////////////////////////////////////////////////////
extern TOKEN_TABLE tokentable[]={
"char",E_CHAR,KEY,
"int",E_INT,KEY,
"float",E_FLOAT,KEY,
"switch",E_SWITCH,KEY,
"case",E_CASE,KEY,
"if",E_IF,KEY,
"else",E_ELSE,KEY,
"for",E_FOR,KEY,
"do",E_DO,KEY,
"while",E_WHILE,KEY,
"break",E_BREAK,KEY,
"return",E_RETURN,KEY,
"cout",E_COUT,KEY,
"cin",E_CIN,KEY,
"{",LBLOCK,FJF,
"}",RBLOCK,FJF,
",",DOU,FJF,
";",EOS,FJF,
"<",LT,CMP,
"<=",LE,CMP,
">",GT,CMP,
">=",GE,CMP,
"==",EQ,CMP,
"!=",NE,CMP,
".",FF,OPE,
"(",LK,OPE,
")",RK,OPE,
"[",LZK,OPE,
"]",RZK,OPE,
"++",INC,OPE,
"--",DEC,OPE,
"<<",LS,OPE,
">>",RS,OPE,
"=",ASS,OPE,
"!",NOT,OPE,
"&&",AND,OPE,
"||",OR,OPE,
"+",ADD,OPE,
"-",SUB,OPE,
"*",MUL,OPE,
"/",DIV,OPE,
"%",MOD,OPE,
"^",POW,OPE,
};
var_value::var_value(const var_value& p)
{
int_value=p.int_value;
float_value=p.float_value;
strcpy(string_value,p.string_value);
v_type=p.v_type;
}
bool operator == (const var_value& _X, const var_value& _Y)
{
if (_X.v_type != _Y.v_type)
{
return false;
}
else
{
switch (_X.v_type)
{
case V_Float:
return (abs(_X.float_value - _Y.float_value) < 0.0001);
break;
case V_Int:
return (_X.int_value == _Y.int_value);
break;
case V_Int:
return !(strcmp(_X.string_value, _Y.string_value));
break;
default:
return false;
}
}
}
bool operator < (const var_value& _X, const var_value& _Y)
{
if (_X.v_type != _Y.v_type)
{
return false;
}
else
{
switch (_X.v_type)
{
case V_Float:
return (_X.float_value < _Y.float_value);
break;
case V_Int:
return (_X.int_value < _Y.int_value);
break;
case V_Int:
return !(strcmp(_X.string_value, _Y.string_value));
break;
default:
return false;
}
}
temp_var_value::temp_var_value(const temp_var_value& p)
{
int_value=p.int_value;
float_value=p.float_value;
strcpy(string_value,p.string_value);
p_int=p.p_int;
p_float=p.p_float;
p_string=p.p_string;
v_type=p.v_type;
}
void Fenxi::Create(char* p,PTOKEN_TABLE ptt,int n)
{
strcpy(pFileName,p);
ifstream fin(pFileName,ios::in|ios::binary);
fin.seekg(0,ios::end);
iFileLength=fin.tellg();
fin.close();
if(iFileLength==0)
throw InterpExc(ERROR_SIZE);
iBlock=0;
LoadBlock();
MoveNext();//指向第一個字元
iYouBiao=0;//置游標於文件頭
curr_pt=0;
prev_pt=0;
cbuff=buff[0];//當前應該分析字元
cbuff1=buff[1];//超前搜索字元
pTokenTable=ptt;
nTableItem=n;//分析表設置
}
void Fenxi::MoveNext()
{
if(iYouBiao==MAX_BUF_LEN-1)//如果當前游標在緩沖區尾
{
iBlock++;
LoadBlock();
cbuff=buff[0];
cbuff1=buff[1];//超前搜索
}
else
{
iYouBiao++;
cbuff=buff[iYouBiao];
if(iYouBiao==MAX_BUF_LEN-1)//超前搜索
{
char temp[2];
temp[1]=0;
ifstream fin(pFileName,ios::in|ios::binary);
fin.seekg(MAX_BUF_LEN*(iBlock+1));
fin.read(temp,1);
int i=fin.gcount();
temp[i]=0;
fin.close();
cbuff1=temp[0];
}
else
cbuff1=buff[iYouBiao+1];
}
curr_pt=GetPt(iBlock,iYouBiao);
}
void Fenxi::MovePrev()
{
if(iYouBiao==0)//如果當前游標在緩沖區頭
{
cbuff1=cbuff;//超前搜索
iBlock--;
LoadBlock();
iYouBiao=MAX_BUF_LEN-1;
cbuff=buff[iYouBiao];
}
else
{
cbuff1=cbuff;//超前搜索
iYouBiao--;
cbuff=buff[iYouBiao];
}
curr_pt=GetPt(iBlock,iYouBiao);
}
void Fenxi::PutBack()
{
GotoPt(prev_pt);
}
void Fenxi::LoadBlock()//裝入一個塊
{
ifstream fin(pFileName,ios::in|ios::binary);
fin.seekg(MAX_BUF_LEN*iBlock);
fin.read(buff,MAX_BUF_LEN);
int i=fin.gcount();
buff[i]=0;
iYouBiao=0;
fin.close();
}
void Fenxi::GotoPt(long pt)
{
if(pt/MAX_BUF_LEN==curr_pt/MAX_BUF_LEN)//如果是在同一個塊內的話
{
curr_pt=pt;
iYouBiao=curr_pt-iBlock*MAX_BUF_LEN;
cbuff=buff[iYouBiao];
}
else//否則要重新裝入內存
{
curr_pt=pt;
iBlock=curr_pt/MAX_BUF_LEN;
LoadBlock();
iYouBiao=curr_pt-iBlock*MAX_BUF_LEN;
cbuff=buff[iYouBiao];
}
if(iYouBiao==MAX_BUF_LEN-1)//超前搜索
{
char temp[2];
temp[1]=0;
ifstream fin(pFileName,ios::in|ios::binary);
fin.seekg(MAX_BUF_LEN*(iBlock+1));
fin.read(temp,1);
int i=fin.gcount();
temp[i]=0;
fin.close();
cbuff1=temp[0];
}
else
cbuff1=buff[iYouBiao+1];
}
void Fenxi::GetToken()
{
prev_pt=curr_pt;//保存前一個的位置
char *temp; //利用一個指針向字元里寫內容
item=UNDEF;type=UDF;
temp = stoken;
*temp = '\0';
// 如果當前字元是空格且未到文件末
while(isspace(cbuff) && cbuff) MoveNext();
// 跳過行
while(cbuff == '\r') {
MoveNext();
MoveNext();
while(isspace(cbuff) && cbuff) MoveNext();
}
// 是否結尾
if(cbuff == '\0') {
*stoken = '\0';
item = END;
type=NON;
return ;
}
// 檢查{}標識符
if(strchr("{}", cbuff)) {
stoken[0]=cbuff;
stoken[1]='\0';
type=FJF;
if(cbuff=='{')
item=LBLOCK;
else
item=RBLOCK;
MoveNext();//指向下一個字元
return ;
}
// 檢查注釋信息
if(cbuff == '/')
if(cbuff1 == '*') { // /*注釋符
MoveNext();
MoveNext();
do { // 找到結尾
while(cbuff != '*') MoveNext();
MoveNext();
} while (cbuff != '/');
MoveNext();
GetToken();
return;
} else if(cbuff1 == '/') { // is a // CMPment
MoveNext();
MoveNext();
// Find end of CMPment.
while(cbuff != '\r' && cbuff != '\0') MoveNext();
if(cbuff == '\r') {MoveNext();MoveNext();}
GetToken();
return;
}
// 檢查雙操作符
if(strchr("!<>=+-&|", cbuff)) {
switch(cbuff) {
case '|':
if(cbuff1 == '|') {
MoveNext();MoveNext();
*temp = '|';
temp++;
*temp = '|';
temp++;
*temp = '\0';
item=OR;
type=OPE;
}
break;
case '&':
if(cbuff1 == '&') {
MoveNext();MoveNext();
*temp = '&';
temp++;
*temp = '&';
temp++;
*temp = '\0';
item=AND;
type=OPE;
}
break;
case '=':
if(cbuff1 == '=') {
MoveNext();MoveNext();
*temp = '=';
temp++;
*temp = '=';
temp++;
*temp = '\0';
item=EQ;
type=CMP;
}
break;
case '!':
if(cbuff1 == '=') {
MoveNext();MoveNext();
*temp = '!';
temp++;
*temp = '=';
temp++;
*temp = '\0';
item=NE;
type=CMP;
}
break;
case '<':
if(cbuff1 == '=') {
MoveNext();MoveNext();
*temp = '<';
temp++;
*temp = '=';
item=LE;
type=CMP;
}
else if(cbuff1 == '<') {
MoveNext();MoveNext();
*temp = '<';
temp++;
*temp = '<';
item=LS;
type=OPE;
}
else {
MoveNext();
*temp = '<';
item=LT;
type=CMP;
}
temp++;
*temp = '\0';
break;
case '>':
if(cbuff1 == '=') {
MoveNext();MoveNext();
*temp = '>';
temp++;
*temp = '=';
item=GE;
type=CMP;
} else if(cbuff1 == '>') {
MoveNext();MoveNext();
*temp = '>';
temp++;
*temp = '>';
item=RS;
type=OPE;
}
else {
MoveNext();
*temp = '>';
item=GT;
type=CMP;
}
temp++;
*temp = '\0';
break;
case '+':
if(cbuff1 == '+') {
MoveNext();MoveNext();
*temp = '+';
temp++;
*temp = '+';
temp++;
*temp = '\0';
item=INC;
type=OPE;
}
break;
case '-':
if(cbuff1 == '-') {
MoveNext();MoveNext();
*temp = '-';
temp++;
*temp = '-';
temp++;
*temp = '\0';
item=DEC;
type=OPE;
}
break;
}
if(*stoken) return;
}
// 其它運算符號
if(strchr("+-*^/=().[]|!%", cbuff)) {
type=OPE;
switch(cbuff){
case '+':
item=ADD;break;
case '-':
item=SUB;break;
case '*':
item=MUL;break;
case '/':
item=DIV;break;
case '=':
item=ASS;break;
case '(':
item=LK;break;
case ')':
item=RK;break;
case '[':
item=LZK;break;
case ']':
item=RZK;break;
case '.':
item=FF;break;
case '|':
item=UNDEF;type=UDF;break;
case '!':
item=NOT;break;
case '%':
item=MOD;break;
}
*temp = cbuff;
MoveNext();
temp++;
*temp = '\0';
return ;
}
// 分界符號
if(strchr(";,#:", cbuff)) {
type=FJF;
switch(cbuff){
case ';':
item=EOS;break;
case ',':
item=DOU;break;
case ':':
item=MAO;break;
}
*temp = cbuff;
MoveNext();
temp++;
*temp = '\0';
return ;
}
// 讀取一個字元串
if(cbuff == '"') {
MoveNext();
while(cbuff != '"' && cbuff != '\r' && cbuff) {
// Check for \n escape sequence.
if(cbuff == '\\') {
if(cbuff1 == 'n') {
MoveNext();
*temp++ = '\n';
}
}
else if((temp - stoken) < MAX_T_LEN)
*temp++ = cbuff;
MoveNext();
}
if(cbuff == '\r' || cbuff == 0)
throw InterpExc(SYNTAX);
MoveNext(); *temp = '\0';
item=STRING;
type=STR;
return ;
}
// 讀取一個數字
if(isdigit(cbuff)) {
while((cbuff>='0'&&cbuff<='9')||(cbuff=='.')) {
if((temp - stoken) < MAX_T_LEN)
*temp++ = cbuff;
MoveNext();
}
*temp = '\0';
item=NUMBER;
type=NUM;
return ;
}
// Read identifier or keyword.
if(isalpha(cbuff)) {
while(!isdelim(cbuff)) {
if((temp - stoken) < MAX_T_LEN)
*temp++ = cbuff;
MoveNext();
}
item=E_TEMP;
}
*temp = '\0';
// Determine if token is a keyword or identifier.
if(item == E_TEMP) { // convert to internal form
if(KeyLookUp(stoken,item)) type=KEY; // is a keyword
else {type = IDE;item=IDENTIFIER;}
}
if(type==UDF)
throw InterpExc(SYNTAX);
}
bool Fenxi::KeyLookUp(char *s,Token_Item &it){
int i;
// char *p;
// 轉為小寫字母
// p = s;
// while(*p) { *p = tolower(*p); p++; }
for(i=0; i<nTableItem; i++) {
if((tokentable[i].type==KEY)&&!strcmp(tokentable[i].name, s))
{
it=tokentable[i].token;
return true;
}
}
return false;
}
// 符號檢查
bool Fenxi::isdelim(char c)
{
if(strchr(" !:;,+-<>/*^=().|&[]\"%", c) || c == 9 ||
c == '\r' || c == 0) return true;
return false;
}