|
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 |