#ifndef ACTIONSANDRULES_H #define ACTIONSANDRULES_H ///////////////////////////////////////////////////////////////////// // ActionsAndRules.h - declares new parsing rules and actions // // ver 2.0 // // Language: Visual C++ 2008, SP1 // // Platform: Dell Precision T7400, Vista Ultimate SP1 // // Application: Prototype for CSE687 Pr1, Sp09 // // Author: Jim Fawcett, CST 4-187, Syracuse University // // (315) 443-3948, jfawcett@twcny.rr.com // ///////////////////////////////////////////////////////////////////// /* Module Operations: ================== This module defines several action classes. Its classes provide specialized services needed for specific applications. The modules Parser, SemiExpression, and Tokenizer, are intended to be reusable without change. This module provides a place to put extensions of these facilities and is not expected to be reusable. Public Interface: ================= Toker t(someFile); // create tokenizer instance SemiExp se(&t); // create a SemiExp attached to tokenizer Parser parser(se); // now we have a parser Rule1 r1; // create instance of a derived Rule class Action1 a1; // create a derived action r1.addAction(&a1); // register action with the rule parser.addRule(&r1); // register rule with parser while(se.getSemiExp()) // get semi-expression parser.parse(); // and parse it Build Process: ============== Required files - Parser.h, Parser.cpp, ScopeStack.h, ScopeStack.cpp, ActionsAndRules.h, ActionsAndRules.cpp, ConfigureParser.cpp, ItokCollection.h, SemiExpression.h, SemiExpression.cpp, tokenizer.h, tokenizer.cpp Build commands (either one) - devenv CodeAnalysis.sln - cl /EHsc /DTEST_PARSER parser.cpp ActionsAndRules.cpp \ semiexpression.cpp tokenizer.cpp /link setargv.obj Maintenance History: ==================== ver 2.0 : 01 Jun 11 - added processing on way to building strong code analyzer ver 1.1 : 17 Jan 09 - changed to accept a pointer to interfaced ITokCollection instead of a SemiExpression ver 1.0 : 12 Jan 06 - first release */ // #include #include #include #include "Parser.h" #include "ITokCollection.h" #include "ScopeStack.h" #include "Tokenizer.h" #include "SemiExpression.h" /////////////////////////////////////////////////////////////// // ScopeStack element is application specific struct element { std::string type; std::string name; size_t lineCount; std::string show() { std::ostringstream temp; temp << "("; temp << type; temp << ", "; temp << name; temp << ", "; temp << lineCount; temp << ")"; return temp.str(); } }; /////////////////////////////////////////////////////////////// // Repository instance is used to share resources // among all actions. class Repository // application specific { ScopeStack stack; Toker* p_Toker; std::queue* p_Queue; public: Repository(Toker* pToker, std::queue* pQ) { p_Toker = pToker; p_Queue = pQ; } ScopeStack& scopeStack() { return stack; } Toker* Toker() { return p_Toker; } std::queue* Queue() { return p_Queue; } size_t lineCount() { return (size_t)(p_Toker->lines()); } }; /////////////////////////////////////////////////////////////// // rule to detect beginning of anonymous scope class BeginningOfScope : public IRule { public: bool doTest(ITokCollection*& pTc) { //std::cout << "\n--BeginningOfScope rule"; if(pTc->find("{") < pTc->length()) { doActions(pTc); return false; } return false; } }; /////////////////////////////////////////////////////////////// // action to handle scope stack at end of scope class HandlePush : public IAction { Repository* p_Repos; public: HandlePush(Repository* pRepos) { p_Repos = pRepos; } void doAction(ITokCollection*& pTc) { element elem; elem.type = "unknown"; elem.name = "anonymous"; elem.lineCount = p_Repos->lineCount(); p_Repos->scopeStack().push(elem); } }; /////////////////////////////////////////////////////////////// // rule to detect end of scope class EndOfScope : public IRule { public: bool doTest(ITokCollection*& pTc) { //std::cout << "\n--EndOfScope rule"; if(pTc->find("}") < pTc->length()) { doActions(pTc); return false; } return false; } }; /////////////////////////////////////////////////////////////// // action to handle scope stack at end of scope class HandlePop : public IAction { Repository* p_Repos; public: HandlePop(Repository* pRepos) { p_Repos = pRepos; } void doAction(ITokCollection*& pTc) { std::ostringstream out; if(p_Repos->scopeStack().size() == 0) return; element elem = p_Repos->scopeStack().pop(); if(elem.type == "function") { //std::cout << "\nHandlePop"; //std::cout << "\n--popping at line count = " << p_Repos->lineCount(); out << "Function " << elem.name << ", lines = " << p_Repos->lineCount() - elem.lineCount + 1; std::queue* pQueue = p_Repos->Queue(); if(pQueue == nullptr) std::cout << "\n " << out.str(); else pQueue->push(out.str()); } } }; /////////////////////////////////////////////////////////////// // rule to detect preprocessor statements class PreprocStatement : public IRule { public: bool doTest(ITokCollection*& pTc) { //std::cout << "\n--PreprocStatement rule"; if(pTc->find("#") < pTc->length()) { doActions(pTc); return true; } return false; } }; /////////////////////////////////////////////////////////////// // action to print preprocessor statement to console class PrintPreproc : public IAction { Repository* p_Repos; public: PrintPreproc(Repository* pRepos) : p_Repos(pRepos) {} void doAction(ITokCollection*& pTc) { std::ostringstream out; out << "Preproc Stmt: " << pTc->show().c_str(); std::queue* pQueue = p_Repos->Queue(); if(pQueue == nullptr) std::cout << "\n\n " << out.str(); else pQueue->push(out.str()); } }; /////////////////////////////////////////////////////////////// // rule to detect function definitions class FunctionDefinition : public IRule { public: bool isSpecialKeyWord(const std::string& tok) { const static std::string keys[] = { "for", "while", "switch", "if", "catch" }; for(int i=0; i<5; ++i) if(tok == keys[i]) return true; return false; } bool doTest(ITokCollection*& pTc) { ITokCollection& tc = *pTc; if(tc[tc.length()-1] == "{") { size_t len = tc.find("("); if(len < tc.length() && !isSpecialKeyWord(tc[len-1])) { //std::cout << "\n--FunctionDefinition rule"; doActions(pTc); return true; } } return false; } }; /////////////////////////////////////////////////////////////// // action to push function name onto ScopeStack class PushFunction : public IAction { Repository* p_Repos; public: PushFunction(Repository* pRepos) { p_Repos = pRepos; } void doAction(ITokCollection*& pTc) { // pop anonymous scope p_Repos->scopeStack().pop(); // push function scope std::string name = (*pTc)[pTc->find("(") - 1]; element elem; elem.type = "function"; elem.name = name; elem.lineCount = p_Repos->lineCount(); p_Repos->scopeStack().push(elem); } }; /////////////////////////////////////////////////////////////// // action to send semi-expression that starts a function def // to console class PrintFunction : public IAction { Repository* p_Repos; public: PrintFunction(Repository* pRepos) : p_Repos(pRepos) {} void doAction(ITokCollection*& pTc) { std::ostringstream out; out << "\n\n FuncDef Stmt: " << pTc->show().c_str(); std::queue* pQueue = p_Repos->Queue(); if(pQueue == nullptr) std::cout << "\n\n " << out.str(); else pQueue->push(out.str()); } }; /////////////////////////////////////////////////////////////// // action to send signature of a function def to console class PrettyPrintFunction : public IAction { Repository* p_Repos; public: PrettyPrintFunction(Repository* pRepos) : p_Repos(pRepos) {} void doAction(ITokCollection*& pTc) { std::ostringstream out; pTc->remove("public"); pTc->remove(":"); pTc->trimFront(); int len = pTc->find(")"); out << "\n\n Pretty Stmt: "; std::queue* pQueue = p_Repos->Queue(); if(pQueue == nullptr) std::cout << out.str(); else pQueue->push(out.str()); for(int i=0; i* pQueue = p_Repos->Queue(); if(pQueue == nullptr) std::cout << out.str(); else pQueue->push(out.str()); } } }; #endif