diff -r 000000000000 -r f58d6ec98e88 cdlcompilertoolkit/src/CdlTkParser.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cdlcompilertoolkit/src/CdlTkParser.cpp Thu Dec 17 09:14:18 2009 +0200 @@ -0,0 +1,362 @@ +/* +* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ +#include "CdlCompilerToolkit/CdlTkProcess.h" +#include "CdlTkPriv.h" +#include +#include +#include +using namespace std; + +namespace CdlCompilerToolkit { + +// +// SyntaxErr +// + +class SyntaxErr : public CdlCompilerToolkitErr + { +public: + SyntaxErr(const string& aFileName, int aLineNo, string aErr); + void Show(ostream& aStream) const; +private: + string iFileName; + int iLineNo; + string iErr; + }; + +SyntaxErr::SyntaxErr(const string& aFileName, int aLineNo, string aErr) +: iFileName(aFileName), iLineNo(aLineNo), iErr(aErr) + { + } + +void SyntaxErr::Show(ostream& aStream) const + { + aStream << iFileName << "(" << iLineNo << ")" << " : error : " << iErr << endl; + } + + +// +// CCdlTkCdlFileParser +// + +CCdlTkCdlFileParser::CCdlTkCdlFileParser(const string& aFileName) +: iFileName(aFileName) + { + } + +CCdlTkCdlFileParser::~CCdlTkCdlFileParser() + { + CloseStream(); + } + +void CCdlTkCdlFileParser::Process() + { + throw CdlTkAssert("Sorry, CCdlTkCdlFileParser::Process() does not exist, call LoadAndParse() instead"); + } + +auto_ptr CCdlTkCdlFileParser::LoadAndParse(bool aMergeExtensions) + { + OpenStream(); + iState = EHeader; + auto_ptr cdl(new CCdlTkInterface); + cdl->SetFileName(iFileName); + ParseStream(*cdl.get()); + CloseStream(); + if (aMergeExtensions) + cdl->MergeExtensions(); + return cdl; + } + +void CCdlTkCdlFileParser::OpenStream() + { + CdlTkUtil::OpenInput(iIn, iFileName); + iCurrentSourceLineNum = 0; + } + +void CCdlTkCdlFileParser::ParseStream(CCdlTkInterface& aCdl) + { + CCdlTkInterface* cdl = &aCdl; + while (!iIn.eof()) + { + string line = GetLine(); + TParseState newState = iState; + if (IsSectionBoundary(line, newState)) + { + iState = newState; + if (iState == EHeader && !(cdl->Header() == CCdlTkInterfaceHeader())) + { + CCdlTkInterface* ext = new CCdlTkInterface; + ext->SetBase(cdl); + cdl->SetExtension(ext); + cdl = ext; + } + // iApiBuf and iComment have to be cleared over a section boundary + iApiBuf = ""; + iComment = ""; + } + else + { + switch (iState) + { + case EHeader: + ParseHeader(*cdl, line); + break; + case ECpp: + ParseCpp(*cdl, line); + break; + case ETranslation: + ParseTranslationLine(*cdl, line); + break; + case EApi: + ParseApi(*cdl, line); + break; + default: + return; + } + } + } + } + +void CCdlTkCdlFileParser::CloseStream() + { + iIn.close(); + } + +void CCdlTkCdlFileParser::ParseHeader(CCdlTkInterface& aCdl, const string& aLine) + { + string val; + if (MatchLineStart(aLine, "Name:", val)) + { + aCdl.Header().SetName(val); + } + else if (MatchLineStart(aLine, "Version:", val)) + { + int major, minor; + char c; + stringstream s(val); + s >> major >> c >> minor; + if (c != '.' || !s.eof()) + SyntaxError(string("Invalid version number ") + val); + aCdl.Header().SetVersion(CCdlTkInterfaceHeader::CVersion(major, minor)); + } + else if (MatchLineStart(aLine, "UID:", val)) + { + aCdl.Header().SetUid(CdlTkUtil::ParseInt(val)); + } + else if (MatchLineStart(aLine, "Flag:", val)) + { + aCdl.Header().Flags().SetFlag(val); + } + } + +void CCdlTkCdlFileParser::ParseCpp(CCdlTkInterface& aCdl, const string& aLine) + { + aCdl.Cpp().push_back(aLine); + } + +void CCdlTkCdlFileParser::ParseTranslationLine(CCdlTkInterface& aCdl, const string& aLine) + { + string line = aLine; + StripComments(line, iComment); + CdlTkUtil::StripLeadingAndTrailingWhitespace(line); + if (!line.empty()) + { + CCdlTkDataTypeTranslation trans; + ParseTranslationText(trans, line); + aCdl.DataTypeTranslations().push_back(trans); + } + } + +void CCdlTkCdlFileParser::ParseApi(CCdlTkInterface& aCdl, const string& aLine) + { + string line = aLine; + StripComments(line, iComment); + if (!line.empty()) + { + // add the line to the API buffer + CdlTkUtil::AppendString(iApiBuf, line); + int pos; + // extract API declarations from the API buffer, separated by semi-colons + while ((pos = iApiBuf.find_first_of(';')) != string::npos) + { + // extract API declaration from API buf and create API from it + line = iApiBuf.substr(0, pos); + CdlTkUtil::StripLeadingAndTrailingWhitespace(line); + auto_ptr api(CreateApi(aCdl, line)); + aCdl.ApiList().push_back(api.get()); + api.release(); + // remove API declaration from API buf + iApiBuf = iApiBuf.substr(pos+1); + } + } + } + +string CCdlTkCdlFileParser::GetLine() + { + string line; + getline(iIn, line); + iCurrentSourceLineNum++; + return line; + } + +bool CCdlTkCdlFileParser::IsSectionBoundary(const string& aLine, TParseState& aState) + { + string section; + bool isBoundary = MatchLineStart(aLine, KSectionBoundary, section); + if (!isBoundary) + return false; + + section = CdlTkUtil::ToLower(section); + + char* sections[] = {"header", "c++", "translation", "api", "end"}; + TParseState s; + for (s = EHeader; s < EParseStateCount; s = TParseState(s+1)) + if (section == sections[s]) + break; + if (s < EParseStateCount) + aState = s; + else + SyntaxError("Unrecognised section type : " + section); + + return true; + } + +bool CCdlTkCdlFileParser::MatchLineStart(const string& aLine, const string& aHeader, string& aVal) + { + if (aLine.size() < aHeader.size() || aLine.substr(0, aHeader.size()) != aHeader) + return false; + + aVal = aLine.substr(aHeader.size()); + StripComments(aVal, iComment); + CdlTkUtil::StripLeadingAndTrailingWhitespace(aVal); + return true; + } + +void CCdlTkCdlFileParser::StripComments(string& aStr, string& aComment) + { + int pos = aStr.find(KCommentStart); + if (pos != string::npos) + { + aComment += aStr.substr(pos) + "\n"; + } + aStr = aStr.substr(0, pos); + } + +auto_ptr CCdlTkCdlFileParser::CreateApi(CCdlTkInterface& aCdl, string& aLine) + { + auto_ptr pApi; + bool isFunc = (aLine[aLine.size()-1] == ')'); // function APIs end with ')', data APIs don't + if (isFunc) + { + auto_ptr pFuncApi(new CCdlTkFunctionApi(aCdl)); + int paramStart = aLine.find('('); + if (paramStart == string::npos) + SyntaxError("function has missing '('"); + string params = aLine.substr(paramStart); + aLine = aLine.substr(0, paramStart); + params = params.substr(1, params.size()-2); // -2 for opening and closing brackets + CdlTkUtil::StripLeadingAndTrailingWhitespace(params); + ParseApiParams(pFuncApi->Params(), params); + pApi = auto_ptr(pFuncApi.release()); + } + else + { + pApi = auto_ptr(new CCdlTkDataApi(aCdl)); + } + string name, type, defaultValue; + ParseNameTypeAndDefaultValue(aLine, name, type, defaultValue); + pApi->SetName(name); + pApi->SetReturnType(type); + pApi->SetSourceFileLineNum(iCurrentSourceLineNum); + pApi->SetComment(iComment); + iComment = ""; + return pApi; + } + +void CCdlTkCdlFileParser::ParseApiParams(CCdlTkApiParams& aParams, string& aList) + { + while (aList.size()) + { + int pos = aList.find(','); + string param = aList.substr(0, pos); + aList = aList.substr(param.size() + (pos == string::npos ? 0 : 1)); + CdlTkUtil::StripLeadingAndTrailingWhitespace(aList); + + string name, type, defaultValue; + ParseNameTypeAndDefaultValue(param, name, type, defaultValue); + + aParams.push_back(CCdlTkApiParam(type, name, defaultValue)); + } + } + +void CCdlTkCdlFileParser::ParseNameTypeAndDefaultValue(string& aStr, string& aName, string& aType, string& aDefaultValue) + { + CdlTkUtil::StripLeadingAndTrailingWhitespace(aStr); + int eq = aStr.find_last_of(KEqualsSign); + if(eq != string::npos) + { + aDefaultValue = aStr.substr(eq + 1); + CdlTkUtil::StripLeadingAndTrailingWhitespace(aDefaultValue); + + aStr = aStr.substr(0, eq); + CdlTkUtil::StripLeadingAndTrailingWhitespace(aStr); + } + + int pos = aStr.find_last_not_of(KCpp); + aName = aStr.substr(pos + 1); + aStr = aStr.substr(0, pos); + + CdlTkUtil::StripLeadingAndTrailingWhitespace(aStr); + aType = aStr; + } + +void CCdlTkCdlFileParser::ParseTranslationText(CCdlTkDataTypeTranslation& aTrans, string& aLine) + { + int pos1 = aLine.find('#'); + if (pos1 == string::npos) + SyntaxError("First # not found"); + int pos2 = aLine.find('#', pos1+1); + if (pos2 == string::npos) + SyntaxError("Second # not found"); + if (aLine.find('#', pos2+1) != string::npos) + SyntaxError("Third # found"); + + string type = aLine.substr(0, pos1++); + CdlTkUtil::StripLeadingAndTrailingWhitespace(type); + + string defn = aLine.substr(pos1, pos2-pos1); + CdlTkUtil::StripLeadingAndTrailingWhitespace(defn); + if (defn.find("aName") == string::npos) + SyntaxError("\"aName\" not found in definition"); + + string ptrRef = aLine.substr(pos2+1); + CdlTkUtil::StripLeadingAndTrailingWhitespace(ptrRef); + if (ptrRef.find("aName") == string::npos) + SyntaxError("\"aName\" not found in pointer reference"); + + aTrans.SetType(type); + aTrans.SetDefinition(defn); + aTrans.SetPointerReference(ptrRef); + } + +void CCdlTkCdlFileParser::SyntaxError(const string& aErr) + { + throw SyntaxErr(iFileName, iCurrentSourceLineNum, aErr); + } + + +} // end of namespace CdlCompilerToolkit