cdlcompilertoolkit/src/CdlTkParser.cpp
changeset 0 f58d6ec98e88
child 1 b700e12870ca
equal deleted inserted replaced
-1:000000000000 0:f58d6ec98e88
       
     1 /*
       
     2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:
       
    15 *
       
    16 */
       
    17 #include "CdlCompilerToolkit/CdlTkProcess.h"
       
    18 #include "CdlTkPriv.h"
       
    19 #include <iomanip>
       
    20 #include <sstream>
       
    21 #include <iostream>
       
    22 using namespace std;
       
    23 
       
    24 namespace CdlCompilerToolkit {
       
    25 
       
    26 //
       
    27 // SyntaxErr
       
    28 //
       
    29 
       
    30 class SyntaxErr : public CdlCompilerToolkitErr
       
    31 	{
       
    32 public:
       
    33 	SyntaxErr(const string& aFileName, int aLineNo, string aErr);
       
    34 	void Show(ostream& aStream) const;
       
    35 private:
       
    36 	string iFileName;
       
    37 	int iLineNo;
       
    38 	string iErr;
       
    39 	};
       
    40 
       
    41 SyntaxErr::SyntaxErr(const string& aFileName, int aLineNo, string aErr)
       
    42 : iFileName(aFileName), iLineNo(aLineNo), iErr(aErr)
       
    43 	{
       
    44 	}
       
    45 
       
    46 void SyntaxErr::Show(ostream& aStream) const
       
    47 	{
       
    48 	aStream << iFileName << "(" << iLineNo << ")" << " : error : " << iErr << endl;
       
    49 	}
       
    50 
       
    51 
       
    52 //
       
    53 // CCdlTkCdlFileParser
       
    54 //
       
    55 
       
    56 CCdlTkCdlFileParser::CCdlTkCdlFileParser(const string& aFileName) 
       
    57 : iFileName(aFileName)
       
    58 	{
       
    59 	}
       
    60 
       
    61 CCdlTkCdlFileParser::~CCdlTkCdlFileParser()
       
    62 	{
       
    63 	CloseStream();
       
    64 	}
       
    65 
       
    66 void CCdlTkCdlFileParser::Process()
       
    67 	{
       
    68 	throw CdlTkAssert("Sorry, CCdlTkCdlFileParser::Process() does not exist, call LoadAndParse() instead");
       
    69 	}
       
    70 
       
    71 auto_ptr<CCdlTkInterface> CCdlTkCdlFileParser::LoadAndParse(bool aMergeExtensions)
       
    72 	{
       
    73 	OpenStream();
       
    74 	iState = EHeader;
       
    75 	auto_ptr<CCdlTkInterface> cdl(new CCdlTkInterface);
       
    76 	cdl->SetFileName(iFileName);
       
    77 	ParseStream(*cdl.get());
       
    78 	CloseStream();
       
    79 	if (aMergeExtensions)
       
    80 		cdl->MergeExtensions();
       
    81 	return cdl;
       
    82 	}
       
    83 
       
    84 void CCdlTkCdlFileParser::OpenStream()
       
    85 	{
       
    86 	CdlTkUtil::OpenInput(iIn, iFileName);
       
    87 	iCurrentSourceLineNum = 0;
       
    88 	}
       
    89 
       
    90 void CCdlTkCdlFileParser::ParseStream(CCdlTkInterface& aCdl)
       
    91 	{
       
    92 	CCdlTkInterface* cdl = &aCdl;
       
    93 	while (!iIn.eof())
       
    94 		{
       
    95 		string line = GetLine();
       
    96 		TParseState newState = iState;
       
    97 		if (IsSectionBoundary(line, newState))
       
    98 			{
       
    99 			iState = newState;
       
   100 			if (iState == EHeader && !(cdl->Header() == CCdlTkInterfaceHeader()))
       
   101 				{
       
   102 				CCdlTkInterface* ext = new CCdlTkInterface;
       
   103 				ext->SetBase(cdl);
       
   104 				cdl->SetExtension(ext);
       
   105 				cdl = ext;
       
   106 				}
       
   107 			// iApiBuf and iComment have to be cleared over a section boundary
       
   108 			iApiBuf = "";
       
   109 			iComment = "";
       
   110 			}
       
   111 		else
       
   112 			{
       
   113 			switch (iState)
       
   114 				{
       
   115 				case EHeader: 
       
   116 					ParseHeader(*cdl, line); 
       
   117 					break;
       
   118 				case ECpp: 
       
   119 					ParseCpp(*cdl, line); 
       
   120 					break;
       
   121 				case ETranslation: 
       
   122 					ParseTranslationLine(*cdl, line); 
       
   123 					break;
       
   124 				case EApi: 
       
   125 					ParseApi(*cdl, line); 
       
   126 					break;
       
   127 				default: 
       
   128 					return;
       
   129 				}
       
   130 			}
       
   131 		}
       
   132 	}
       
   133 
       
   134 void CCdlTkCdlFileParser::CloseStream()
       
   135 	{
       
   136 	iIn.close();
       
   137 	}
       
   138 
       
   139 void CCdlTkCdlFileParser::ParseHeader(CCdlTkInterface& aCdl, const string& aLine)
       
   140 	{
       
   141 	string val;
       
   142 	if (MatchLineStart(aLine, "Name:", val))
       
   143 		{
       
   144 		aCdl.Header().SetName(val);
       
   145 		}
       
   146 	else if (MatchLineStart(aLine, "Version:", val))
       
   147 		{
       
   148 		int major, minor;
       
   149 		char c;
       
   150 		stringstream s(val);
       
   151 		s >> major >> c >> minor;
       
   152 		if (c != '.' || !s.eof())
       
   153 			SyntaxError(string("Invalid version number ") + val);
       
   154 		aCdl.Header().SetVersion(CCdlTkInterfaceHeader::CVersion(major, minor));
       
   155 		}
       
   156 	else  if (MatchLineStart(aLine, "UID:", val))
       
   157 		{
       
   158 		aCdl.Header().SetUid(CdlTkUtil::ParseInt(val));
       
   159 		}
       
   160 	else if (MatchLineStart(aLine, "Flag:", val))
       
   161 		{
       
   162 		aCdl.Header().Flags().SetFlag(val);
       
   163 		}
       
   164 	}
       
   165 
       
   166 void CCdlTkCdlFileParser::ParseCpp(CCdlTkInterface& aCdl, const string& aLine)
       
   167 	{
       
   168 	aCdl.Cpp().push_back(aLine);
       
   169 	}
       
   170 
       
   171 void CCdlTkCdlFileParser::ParseTranslationLine(CCdlTkInterface& aCdl, const string& aLine)
       
   172 	{
       
   173 	string line = aLine;
       
   174 	StripComments(line, iComment);
       
   175 	CdlTkUtil::StripLeadingAndTrailingWhitespace(line);
       
   176 	if (!line.empty())
       
   177 		{
       
   178 		CCdlTkDataTypeTranslation trans;
       
   179 		ParseTranslationText(trans, line);
       
   180 		aCdl.DataTypeTranslations().push_back(trans);
       
   181 		}
       
   182 	}
       
   183 
       
   184 void CCdlTkCdlFileParser::ParseApi(CCdlTkInterface& aCdl, const string& aLine)
       
   185 	{
       
   186 	string line = aLine;
       
   187 	StripComments(line, iComment);
       
   188 	if (!line.empty())
       
   189 		{
       
   190 		// add the line to the API buffer
       
   191 		CdlTkUtil::AppendString(iApiBuf, line);
       
   192 		int pos;
       
   193 		// extract API declarations from the API buffer, separated by semi-colons
       
   194 		while ((pos = iApiBuf.find_first_of(';')) != string::npos)
       
   195 			{
       
   196 			// extract API declaration from API buf and create API from it
       
   197 			line = iApiBuf.substr(0, pos);
       
   198 			CdlTkUtil::StripLeadingAndTrailingWhitespace(line);
       
   199 			auto_ptr<CCdlTkApi> api(CreateApi(aCdl, line));
       
   200 			aCdl.ApiList().push_back(api.get());
       
   201 			api.release();
       
   202 			// remove API declaration from API buf
       
   203 			iApiBuf = iApiBuf.substr(pos+1);
       
   204 			}
       
   205 		}
       
   206 	}
       
   207 
       
   208 string CCdlTkCdlFileParser::GetLine()
       
   209 	{
       
   210 	string line;
       
   211 	getline(iIn, line);
       
   212 	iCurrentSourceLineNum++;
       
   213 	return line;
       
   214 	}
       
   215 
       
   216 bool CCdlTkCdlFileParser::IsSectionBoundary(const string& aLine, TParseState& aState)
       
   217 	{
       
   218 	string section;
       
   219 	bool isBoundary = MatchLineStart(aLine, KSectionBoundary, section);
       
   220 	if (!isBoundary)
       
   221 		return false;
       
   222 
       
   223 	section = CdlTkUtil::ToLower(section);
       
   224 
       
   225 	char* sections[] = {"header", "c++", "translation", "api", "end"};
       
   226 	TParseState s;
       
   227 	for (s = EHeader; s < EParseStateCount; s = TParseState(s+1))
       
   228 		if (section == sections[s])
       
   229 			break;
       
   230 	if (s < EParseStateCount)
       
   231 		aState = s;
       
   232 	else 
       
   233 		SyntaxError("Unrecognised section type : " + section);
       
   234 
       
   235 	return true;
       
   236 	}
       
   237 
       
   238 bool CCdlTkCdlFileParser::MatchLineStart(const string& aLine, const string& aHeader, string& aVal)
       
   239 	{
       
   240 	if (aLine.size() < aHeader.size() || aLine.substr(0, aHeader.size()) != aHeader)
       
   241 		return false;
       
   242 
       
   243 	aVal = aLine.substr(aHeader.size());
       
   244 	StripComments(aVal, iComment);
       
   245 	CdlTkUtil::StripLeadingAndTrailingWhitespace(aVal);
       
   246 	return true;
       
   247 	}
       
   248 
       
   249 void CCdlTkCdlFileParser::StripComments(string& aStr, string& aComment)
       
   250 	{
       
   251 	int pos = aStr.find(KCommentStart);
       
   252 	if (pos != string::npos)
       
   253 		{
       
   254 		aComment += aStr.substr(pos) + "\n";
       
   255 		}
       
   256 	aStr = aStr.substr(0, pos);
       
   257 	}
       
   258 
       
   259 auto_ptr<CCdlTkApi> CCdlTkCdlFileParser::CreateApi(CCdlTkInterface& aCdl, string& aLine)
       
   260 	{
       
   261 	auto_ptr<CCdlTkApi> pApi;
       
   262 	bool isFunc = (aLine[aLine.size()-1] == ')');	// function APIs end with ')', data APIs don't
       
   263 	if (isFunc)
       
   264 		{
       
   265 		auto_ptr<CCdlTkFunctionApi> pFuncApi(new CCdlTkFunctionApi(aCdl));
       
   266 		int paramStart = aLine.find('(');
       
   267 		if (paramStart == string::npos)
       
   268 			SyntaxError("function has missing '('");
       
   269 		string params = aLine.substr(paramStart);
       
   270 		aLine = aLine.substr(0, paramStart);
       
   271 		params = params.substr(1, params.size()-2);		// -2 for opening and closing brackets
       
   272 		CdlTkUtil::StripLeadingAndTrailingWhitespace(params);
       
   273 		ParseApiParams(pFuncApi->Params(), params);
       
   274 		pApi = auto_ptr<CCdlTkApi>(pFuncApi.release());
       
   275 		}
       
   276 	else
       
   277 		{
       
   278 		pApi = auto_ptr<CCdlTkApi>(new CCdlTkDataApi(aCdl));
       
   279 		}
       
   280 	string name, type, defaultValue;
       
   281 	ParseNameTypeAndDefaultValue(aLine, name, type, defaultValue);
       
   282 	pApi->SetName(name);
       
   283 	pApi->SetReturnType(type);
       
   284 	pApi->SetSourceFileLineNum(iCurrentSourceLineNum);
       
   285 	pApi->SetComment(iComment);
       
   286 	iComment = "";
       
   287 	return pApi;
       
   288 	}
       
   289 
       
   290 void CCdlTkCdlFileParser::ParseApiParams(CCdlTkApiParams& aParams, string& aList)
       
   291 	{
       
   292 	while (aList.size())
       
   293 		{
       
   294 		int pos = aList.find(',');
       
   295 		string param = aList.substr(0, pos);
       
   296 		aList = aList.substr(param.size() + (pos == string::npos ? 0 : 1));
       
   297 		CdlTkUtil::StripLeadingAndTrailingWhitespace(aList);
       
   298 
       
   299 		string name, type, defaultValue;
       
   300 		ParseNameTypeAndDefaultValue(param, name, type, defaultValue);
       
   301 
       
   302 		aParams.push_back(CCdlTkApiParam(type, name, defaultValue));
       
   303 		}
       
   304 	}
       
   305 
       
   306 void CCdlTkCdlFileParser::ParseNameTypeAndDefaultValue(string& aStr, string& aName, string& aType, string& aDefaultValue)
       
   307 	{
       
   308 	CdlTkUtil::StripLeadingAndTrailingWhitespace(aStr);
       
   309 	int eq = aStr.find_last_of(KEqualsSign);
       
   310 	if(eq != string::npos)
       
   311 		{
       
   312 		aDefaultValue = aStr.substr(eq + 1);
       
   313 		CdlTkUtil::StripLeadingAndTrailingWhitespace(aDefaultValue);
       
   314 
       
   315 		aStr = aStr.substr(0, eq);
       
   316 		CdlTkUtil::StripLeadingAndTrailingWhitespace(aStr);
       
   317 		}
       
   318 
       
   319 	int pos = aStr.find_last_not_of(KCpp);
       
   320 	aName = aStr.substr(pos + 1);
       
   321 	aStr = aStr.substr(0, pos);
       
   322 
       
   323 	CdlTkUtil::StripLeadingAndTrailingWhitespace(aStr);
       
   324 	aType = aStr;
       
   325 	}
       
   326 
       
   327 void CCdlTkCdlFileParser::ParseTranslationText(CCdlTkDataTypeTranslation& aTrans, string& aLine)
       
   328 	{
       
   329 	int pos1 = aLine.find('#');
       
   330 	if (pos1 == string::npos)
       
   331 		SyntaxError("First # not found");
       
   332 	int pos2 = aLine.find('#', pos1+1);
       
   333 	if (pos2 == string::npos)
       
   334 		SyntaxError("Second # not found");
       
   335 	if (aLine.find('#', pos2+1) != string::npos)
       
   336 		SyntaxError("Third # found");
       
   337 
       
   338 	string type = aLine.substr(0, pos1++);
       
   339 	CdlTkUtil::StripLeadingAndTrailingWhitespace(type);
       
   340 
       
   341 	string defn = aLine.substr(pos1, pos2-pos1);
       
   342 	CdlTkUtil::StripLeadingAndTrailingWhitespace(defn);
       
   343 	if (defn.find("aName") == string::npos)
       
   344 		SyntaxError("\"aName\" not found in definition");
       
   345 
       
   346 	string ptrRef = aLine.substr(pos2+1);
       
   347 	CdlTkUtil::StripLeadingAndTrailingWhitespace(ptrRef);
       
   348 	if (ptrRef.find("aName") == string::npos)
       
   349 		SyntaxError("\"aName\" not found in pointer reference");
       
   350 
       
   351 	aTrans.SetType(type);
       
   352 	aTrans.SetDefinition(defn);
       
   353 	aTrans.SetPointerReference(ptrRef);
       
   354 	}
       
   355 
       
   356 void CCdlTkCdlFileParser::SyntaxError(const string& aErr)
       
   357 	{
       
   358 	throw SyntaxErr(iFileName, iCurrentSourceLineNum, aErr);
       
   359 	}
       
   360 
       
   361 
       
   362 }	// end of namespace CdlCompilerToolkit