用程序識別C語言的複雜聲明

好久沒發文章了,最近做了個小程序,挺有趣的,發上來大家分享一下。

玩單片機的同志們應該都很熟悉C語言,C語言優點多多,但同時缺點也很多,其中有一個就是C語言的聲明。相信看過一些專業軟體源碼,或者操作系統源碼的同學應該會理解這種痛苦。指針是C語言的精髓,數組也用的很多,當指針,函數,數組在一個聲明中出現,可能會出現形如char *(*(*f(char *(*para)(char *)))[2])();的複雜聲明,C語言的聲明在語言設計的時候就挺反人類,結合順序忽左忽右,別說是新手,老手也很難一眼看出聲明的主體是個什麼鬼。

這裡先推薦一本書《C專家編程》,書中介紹了作者總結的一種識別C語言聲明的一種方法,作者認為通過符號結合的優先順序去判斷聲明的方式晦澀難懂,提出了一種比較方便易學的方法。流程如下:

通過以上方法可以一步步解出聲明的含義,書中還提出了編程對聲明進行解析的設想。正好最近在學習C++,就用C++寫了一個小程序分享給大家,也算是第一次了解面向對象的編程方式,只有內部的一個棧用了類。。

程序效果大概如下:

源碼當然也分享給大家啦。沒怎麼用c++編過程序,發現和c差別挺大的 呵呵..

無聊的時候做點無聊的事也挺有趣的=。=

stack.h 棧實現的源碼n#pragma oncen#include "iostream"ntemplate <typename T>nclass stackn{nprivate:ntint Size;ntstruct Node{nttT data;nttstruct Node *nextNode;nt};nttypedef struct Node* ptrToNode;ntptrToNode bottomNodeP;nnpublic:ntstack()nt{nttSize = 0;nttbottomNodeP = nullptr;nt}nntbool isEmpty()nt{nttreturn (Size == 0);nt}nntvoid push(T &data)nt{nttSize++;nttstruct Node *stackNodeP = new struct Node;nttif (stackNodeP == nullptr)ntttstd::cout << "create new stack node failed" << std::endl;nttstackNodeP->data = data;ntntt//把新數據連接入棧nttstackNodeP->nextNode = bottomNodeP;nttbottomNodeP = stackNodeP;nt}nntT pop()nt{nttT tempData;nttif (this->isEmpty())ntt{ntttstd::cout << "Error! stack is Empty" << std::endl;ntttreturn tempData;ntt}nttelsentt{ntttSize--;tntttptrToNode nodePTemp;nttttempData = bottomNodeP->data;ntttnodePTemp = bottomNodeP->nextNode;nnttt//數據出棧ntttdelete bottomNodeP;ntttbottomNodeP = nodePTemp;ntttreturn tempData;ntt}nt}nntint size()nt{nttreturn Size;nt}nntvirtual ~stack()nt{nt}n};n

主函數源碼n// C language define analysis.cpp : 定義控制台應用程序的入口點。nn#include "stdafx.h"nusing namespace std;nstruct tokenStruct{nt//標記type類型 類型,限定符,標識符,單字元號ntenum typeName { Type, Qualifier, Indentifier, Symbol };nt//結構體內部數據ntstring tokeName;ntenum typeName tokenType;n};nn//nvector<char> symbol = { , (, ), *, ;, ,, [, ]};nvector<string> Type = { "long", "int", "double", "float", "char" ,"unsigned","signed","void"};nvector<string> Qualifier = { "const", "volatile"};nnstack<struct tokenStruct> tokenStack;nn//本地函數nvoid preProcess(string &data);nvoid findFirstIndentifier(string &data);nstring getToken(string &data, vector<char> sby);nvoid classifyString(struct tokenStruct* tokenS, vector<char> syb, vector<string> typ, vector<string> qua);nvoid functionProcess(string &sDefine);nvoid arrayProcess(string &sDefine);nvoid declaratorProcess(string &sDefine);nnint _tmain(int argc, _TCHAR* argv[])n{ntstring cDefine;ntwhile (1)nt{nttcout << "請輸入c語言的聲明字元串:(必須包含結尾的分號)" << endl;ntt//讀取一行包括空格的聲明nttgetline(cin, cDefine);ntt//預處理字元串,消除多餘空格nttpreProcess(cDefine);ntt//找到第一個標識符nttfindFirstIndentifier(cDefine);ntt//會修改cDefine的值,處理主函數nttdeclaratorProcess(cDefine);nttgetline(cin, cDefine);nt}ntreturn 0;n}nn//找到第一個標識符,並把標識符之前的token全部入棧.nvoid findFirstIndentifier(string &data)n{ntstring temp;ntfor (; data != "";)nt{nttstruct tokenStruct tokenTemp;ntttemp = getToken(data, symbol);nttif (temp != " ")ntt{nttttokenTemp.tokeName = temp;nttt//確定token的 typenttt//讀取直到第一個標識符nttt//當為標識符時,進入ifntttclassifyString(&tokenTemp, symbol, Type, Qualifier);ntttif (tokenTemp.tokenType == tokenTemp.Indentifier)nttt{nttttcout << "標識符是" << tokenTemp.tokeName << ",其為";nttttreturn;nttt}ntttelsenttt{ntttttokenStack.push(tokenTemp);nttt}ntt}nt}ntcout << "沒有找到標識符"<<endl;n}nnn//聲明字元串預處理,去掉多餘的空格nvoid preProcess(string &data)n{ntbool spaceFlag = false;ntstring temp;ntfor (unsigned int i = 0; i < data.size(); i++)nt{nttif ((data[i] == ) && spaceFlag)ntt{nntt}nttelsentt{ntttif (data[i] == )spaceFlag = true;ntttelse spaceFlag = false;nttttemp += data[i];ntt}nt}ntdata = temp;n}nn//獲取 token 此函數會修改data去掉已經獲取的token.nstring getToken(string &data, vector<char> sby)n{ntstring tempString;ntfor (unsigned int i = 0; i < data.size(); i++)nt{nttif (isalnum(data[i]))ntt{nttttempString += data[i];ntt}nttelse ntt{ntttfor (unsigned int j = 0; j < sby.size(); j++)nttt{nttttif (data[i] == sby[j])ntttt{ntttttif (tempString == "")nttttt{ntttttttempString += data[i];nttttttdata = data.substr(i+1);nttttt}ntttttelsenttttttdata = data.substr(i);ntttttreturn tempString;ntttt}nttt}tntttcout << "未能識別的符號" << endl;ntttwhile (1);ntt}nt}n}nn//確定token的typenvoid classifyString(struct tokenStruct* tokenS, vector<char> syb, vector<string> typ, vector<string> qua)n{ntfor (unsigned int i = 0; i < syb.size(); i++)nt{nttif ((tokenS->tokeName.size() == 1) && ((tokenS->tokeName)[0]) == syb[i])ntt{nttttokenS->tokenType = tokenS->Symbol;ntttreturn;ntt}nt}ntfor (unsigned int i = 0; i < typ.size(); i++)nt{nttif (tokenS->tokeName == typ[i])ntt{nttttokenS->tokenType = tokenS->Type;ntttreturn;ntt}nt}ntfor (unsigned int i = 0; i < qua.size(); i++)nt{nttif (tokenS->tokeName == qua[i])ntt{nttttokenS->tokenType = tokenS->Qualifier;ntttreturn;ntt}nt}nttokenS->tokenType = tokenS->Indentifier;n}nnvoid functionProcess(string &sDefine)n{ntstruct tokenStruct tokenTemp;ntstring temp;ntint braCount=0;ntcout << "一個函數,函數參數為:";nntfor (; sDefine != "";)nt{ntt//讀取下一個tokenntttemp = getToken(sDefine, symbol);ntt//去掉空格token;ntttokenTemp.tokeName = temp;ntt//參數中若有(則對應獲取一個)nttif (tokenTemp.tokeName == "(")ntttbraCount++;nttif (tokenTemp.tokeName == ")" && braCount>0)ntt{ntttbraCount--;ntttcout << tokenTemp.tokeName;ntt}nttelse if (tokenTemp.tokeName == ")" && braCount==0)ntt{ntttcout << "函數返回為";ntttbreak;ntt}nttelsentttcout << tokenTemp.tokeName;nt}n}nnvoid arrayProcess(string &sDefine)n{ntstruct tokenStruct tokenTemp;ntstring temp;ntcout << "數組";ntfor (; sDefine != "";)nt{ntt//讀取下一個tokennttdontt{nttttemp = getToken(sDefine, symbol);ntt} while (temp == " ");ntttokenTemp.tokeName = temp;nttcout << temp;ntt//確定token的 typenttclassifyString(&tokenTemp, symbol, Type, Qualifier);nttif (tokenTemp.tokenType == tokenTemp.Symbol)ntt{ntttif (tokenTemp.tokeName == "]")nttt{nttttcout << "該數組為";nttttreturn;nttt}ntt}nt}n}nnvoid pointProcess(string &sDefine)n{ntstruct tokenStruct tokenTemp = tokenStack.pop();ntif (tokenTemp.tokeName == "*")nt{nttcout << "一個指針,指向";nt}ntelsent{ntttokenStack.push(tokenTemp);nt}n}nnvoid declaratorProcess(string &sDefine)n{ntstruct tokenStruct tokenTemp;ntstring temp;nnt//讀取下一個token 直到不是空格為止ntdont{ntttemp = getToken(sDefine, symbol);nt} while (temp == " ");nnttokenTemp.tokeName = temp;nt//確定token的 typentclassifyString(&tokenTemp, symbol, Type, Qualifier);ntif (tokenTemp.tokenType == tokenTemp.Symbol)nt{nttif (tokenTemp.tokeName == "[")ntt{ntttsDefine = tokenTemp.tokeName + sDefine;ntttarrayProcess(sDefine);ntt}nttelse if (tokenTemp.tokeName == "(")ntt{ntttfunctionProcess(sDefine);ntt}nttelsentttsDefine = tokenTemp.tokeName + sDefine;nt}nntpointProcess(sDefine);ntwhile (!tokenStack.isEmpty())nt{ntttokenTemp = tokenStack.pop();nttif (tokenTemp.tokeName == "(")ntt{ntttif (getToken(sDefine, symbol) != ")")nttt{nttttcout << endl << "缺少)";nttttreturn;nttt}ntttelsenttt{nttttdeclaratorProcess(sDefine);nttt}ntt}nttelsentt{ntttcout << tokenTemp.tokeName;ntttif (tokenTemp.tokenType == tokenTemp.Type)nttt{nttttcout << "類型";nttt}ntt}nt}n}n

那麼祝大家新年快樂,拜拜了,嘿嘿


推薦閱讀:

iOS 開發中都會使用哪些演算法?
基於五種機器演算法的信用風險評估
通俗易懂講解 直接插入排序

TAG:CC | 算法与数据结构 | 编程 |