hqlparse.cpp 63 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #include "hqlgram.hpp"
  14. #include "hqlfold.hpp"
  15. #include "jiter.ipp"
  16. #include "jptree.hpp"
  17. #include "hqlerrors.hpp"
  18. #include "hqlthql.hpp"
  19. #include "hqlexpr.hpp"
  20. #include "jdebug.hpp"
  21. #include "hqlexpr.ipp"
  22. #include "hqlgram.h"
  23. #define YY_NO_UNISTD_H
  24. #include "hqllex.hpp"
  25. //#define TIMING_DEBUG
  26. #define MAX_LOOP_TIMES 10000
  27. // =========================== local helper functions ===================================
  28. static bool isInModule(HqlLookupContext & ctx, const char* module_name, const char* attr_name);
  29. static StringBuffer& mangle(IErrorReceiver* errReceiver,const char* src, StringBuffer& mangled,bool demangle);
  30. // =========================== CDummyScopeIterator ======================================
  31. class CDummyScopeIterator : public IIterator, public CInterface
  32. {
  33. IXmlScope *parent;
  34. public:
  35. IMPLEMENT_IINTERFACE;
  36. CDummyScopeIterator(IXmlScope *_parent)
  37. {
  38. parent = _parent;
  39. }
  40. ~CDummyScopeIterator ()
  41. {
  42. }
  43. virtual bool first()
  44. {
  45. return true;
  46. };
  47. virtual bool next()
  48. {
  49. return true;
  50. }
  51. virtual bool isValid()
  52. {
  53. return true;
  54. }
  55. virtual IInterface & query()
  56. {
  57. return *parent;
  58. }
  59. virtual IInterface & get()
  60. {
  61. IInterface &ret = query(); ret.Link(); return ret;
  62. }
  63. };
  64. // =========================== CTemplateContext =========================================
  65. class CTemplateContext : implements ITemplateContext, public CInterface
  66. {
  67. HqlLex * lexer;
  68. IXmlScope* m_xmlScope;
  69. int m_startLine,m_startCol;
  70. HqlLookupContext & m_lookupContext;
  71. public:
  72. IMPLEMENT_IINTERFACE;
  73. CTemplateContext(HqlLex * _lexer, HqlLookupContext & lookupContext, IXmlScope* xmlScope, int startLine,int startCol)
  74. : lexer(_lexer), m_xmlScope(xmlScope), m_lookupContext(lookupContext),
  75. m_startLine(startLine), m_startCol(startCol) {}
  76. virtual IXmlScope* queryXmlScope() { return m_xmlScope; }
  77. virtual IEclRepository* queryDataServer() { return m_lookupContext.queryRepository(); }
  78. // convenient functions
  79. virtual bool isInModule(const char* moduleName, const char* attrName) { return ::isInModule(m_lookupContext, moduleName,attrName); }
  80. virtual StringBuffer& getDataType(const char* field, StringBuffer& tgt) { return lexer->doGetDataType(tgt, field, m_startLine, m_startCol); }
  81. virtual StringBuffer& mangle(const char* src, StringBuffer& mangled) { return ::mangle(m_lookupContext.errs,src,mangled,false); }
  82. virtual StringBuffer& demangle(const char* mangled, StringBuffer& demangled) { return ::mangle(m_lookupContext.errs,mangled,demangled,true); }
  83. virtual void reportError(int errNo,const char* format,...);
  84. virtual void reportWarning(int warnNo,const char* format,...);
  85. };
  86. void CTemplateContext::reportError(int errNo,const char* format,...)
  87. {
  88. if (m_lookupContext.errs)
  89. {
  90. va_list args;
  91. va_start(args, format);
  92. StringBuffer msg;
  93. msg.valist_appendf(format,args);
  94. m_lookupContext.errs->reportError(errNo,msg.str(),NULL,m_startLine,m_startCol,0);
  95. va_end(args);
  96. }
  97. }
  98. void CTemplateContext::reportWarning(int warnNo,const char* format,...)
  99. {
  100. if (m_lookupContext.errs)
  101. {
  102. va_list args;
  103. va_start(args, format);
  104. StringBuffer msg;
  105. msg.valist_appendf(format,args);
  106. m_lookupContext.errs->reportWarning(warnNo,msg.str(),NULL,m_startLine,m_startCol,0);
  107. va_end(args);
  108. }
  109. }
  110. // ===================================== HqlLex ============================================
  111. class CHqlParserPseduoScope : public CHqlScope
  112. {
  113. protected:
  114. HqlGram * parser;
  115. public:
  116. CHqlParserPseduoScope(HqlGram * _parser) : CHqlScope(no_privatescope) { parser = _parser; }
  117. virtual IHqlExpression *lookupSymbol(IIdAtom * name, unsigned lookupFlags, HqlLookupContext & ctx)
  118. {
  119. attribute errpos;
  120. errpos.clearPosition();
  121. return parser->lookupSymbol(name, errpos);
  122. }
  123. virtual IHqlScope * queryConcreteScope() { return this; }
  124. virtual bool allBasesFullyBound() const { return true; }
  125. };
  126. // ===================================== HqlLex ============================================
  127. HqlLex::HqlLex(HqlGram *parser, IFileContents * contents, IXmlScope *_xmlScope, IHqlExpression *_macroExpr)
  128. : yyParser(parser), xmlScope(LINK(_xmlScope)), macroExpr(_macroExpr), sourcePath(contents->querySourcePath())
  129. {
  130. assertex(parser);
  131. init(contents);
  132. }
  133. void HqlLex::init(IFileContents * _text)
  134. {
  135. text.set(_text);
  136. inmacro = NULL;
  137. parentLex = NULL;
  138. inComment = false;
  139. inCpp = false;
  140. hasHashbreak = false;
  141. encrypted = false;
  142. loopTimes = 0;
  143. skipping = 0;
  144. macroGathering = 0;
  145. forLoop = NULL;
  146. size32_t len = _text->length();
  147. yyBuffer = new char[len+2]; // Include room for \0 and another \0 that we write beyond the end null while parsing
  148. memcpy(yyBuffer, text->getText(), len);
  149. yyBuffer[len] = '\0';
  150. yyBuffer[len+1] = '\0';
  151. yyLineNo = 1;
  152. yyPosition = 0;
  153. yyColumn = 1;
  154. yyStartPos = 0;
  155. lastToken = 0;
  156. eclyylex_init(&scanner);
  157. eclyy_scan_buffer(yyBuffer, len+2, scanner);
  158. }
  159. ///////////////////////////////////////////////////
  160. // public destructor
  161. //
  162. HqlLex::~HqlLex()
  163. {
  164. eclyylex_destroy(scanner);
  165. scanner = NULL;
  166. delete[] yyBuffer;
  167. ::Release(xmlScope);
  168. ::Release(macroExpr);
  169. if (inmacro) delete inmacro;
  170. ::Release(forLoop);
  171. }
  172. char* HqlLex::get_yyText(void)
  173. {
  174. if (inmacro)
  175. return inmacro->get_yyText();
  176. return eclyyget_text(scanner);
  177. }
  178. IFileContents* HqlLex::query_FileContents(void)
  179. {
  180. if (inmacro)
  181. return inmacro->query_FileContents();
  182. return text;
  183. }
  184. bool HqlLex::isMacroActive(IHqlExpression *expr)
  185. {
  186. if (expr==macroExpr)
  187. return true;
  188. else if (parentLex)
  189. return parentLex->isMacroActive(expr);
  190. else
  191. return false;
  192. }
  193. bool HqlLex::assertNext(YYSTYPE & returnToken, int expected, unsigned code, const char * msg)
  194. {
  195. if (yyLex(returnToken, false,0) != expected)
  196. {
  197. reportError(returnToken, code, "%s", msg);
  198. returnToken.release();
  199. return false;
  200. }
  201. return true;
  202. }
  203. bool HqlLex::assertNextOpenBra()
  204. {
  205. YYSTYPE tempToken;
  206. return assertNext(tempToken, '(', ERR_EXPECTED_LEFTCURLY, "( expected");
  207. }
  208. bool HqlLex::assertNextComma()
  209. {
  210. YYSTYPE tempToken;
  211. return assertNext(tempToken, ',', ERR_EXPECTED_COMMA, ", expected");
  212. }
  213. StringBuffer &HqlLex::getTokenText(StringBuffer &ret)
  214. {
  215. if (inmacro)
  216. return inmacro->getTokenText(ret);
  217. return ret.append(yyPosition - yyStartPos, yyBuffer+yyStartPos);
  218. }
  219. IHqlExpression *HqlLex::lookupSymbol(IIdAtom * name, const attribute& errpos)
  220. {
  221. return yyParser->lookupSymbol(name, errpos);
  222. }
  223. unsigned HqlLex::hex2digit(char c)
  224. {
  225. if (c >= 'a')
  226. return (c - 'a' + 10);
  227. else if (c >= 'A')
  228. return (c - 'A' + 10);
  229. return (c - '0');
  230. }
  231. __int64 HqlLex::str2int64(unsigned len, const char * digits, unsigned base)
  232. {
  233. __int64 value = 0;
  234. while (len--)
  235. {
  236. char c = *digits++;
  237. value = value * base + hex2digit(c);
  238. }
  239. return value;
  240. }
  241. void HqlLex::hex2str(char * target, const char * digits, unsigned len)
  242. {
  243. while (len)
  244. {
  245. *target++ = (hex2digit(digits[0]) << 4) | hex2digit(digits[1]);
  246. len -= 2;
  247. digits += 2;
  248. }
  249. }
  250. IHqlExpression * HqlLex::createIntegerConstant(__int64 value, bool isSigned)
  251. {
  252. return createConstant(createIntValue(value, makeIntType(8, isSigned)));
  253. }
  254. void HqlLex::pushText(const char *s, int startLineNo, int startColumn)
  255. {
  256. #ifdef TIMING_DEBUG
  257. MTIME_SECTION(timer, "HqlLex::pushText");
  258. #endif
  259. Owned<IFileContents> macroContents = createFileContentsFromText(s, sourcePath);
  260. inmacro = new HqlLex(yyParser, macroContents, NULL, NULL);
  261. inmacro->set_yyLineNo(startLineNo);
  262. inmacro->set_yyColumn(startColumn);
  263. }
  264. void HqlLex::pushText(const char *s)
  265. {
  266. #ifdef TIMING_DEBUG
  267. MTIME_SECTION(timer, "HqlLex::pushText");
  268. #endif
  269. Owned<IFileContents> macroContents = createFileContentsFromText(s, sourcePath);
  270. inmacro = new HqlLex(yyParser, macroContents, NULL, NULL);
  271. inmacro->set_yyLineNo(yyLineNo);
  272. inmacro->set_yyColumn(yyColumn);
  273. #if defined (TRACE_MACRO)
  274. PrintLog("MACRO>> inmacro %p created for \"%s\" for macro parameters.\n",inmacro,s);
  275. #endif
  276. }
  277. void HqlLex::setMacroParam(const YYSTYPE & errpos, IHqlExpression* funcdef, StringBuffer& curParam, IIdAtom * argumentId, unsigned& parmno,IProperties *macroParms)
  278. {
  279. IHqlExpression * formals = queryFunctionParameters(funcdef);
  280. IHqlExpression * defaults = queryFunctionDefaults(funcdef);
  281. unsigned numFormals = formals->numChildren();
  282. unsigned thisParam = (unsigned)-1;
  283. if (argumentId)
  284. {
  285. IAtom * argumentName = argumentId->lower();
  286. unsigned argNum = 0;
  287. for (unsigned i=0; i < numFormals; i++)
  288. {
  289. if (formals->queryChild(i)->queryName() == argumentName)
  290. {
  291. argNum = i+1;
  292. break;
  293. }
  294. }
  295. if (argNum == 0)
  296. reportError(errpos, ERR_NAMED_PARAM_NOT_FOUND, "Named parameter '%s' not found in macro", argumentId->str());
  297. else
  298. thisParam = argNum;
  299. }
  300. else
  301. thisParam = ++parmno;
  302. if (thisParam <= numFormals)
  303. {
  304. IHqlExpression* formal = formals->queryChild(thisParam-1);
  305. if (curParam.length()==0)
  306. {
  307. IHqlExpression* def = queryDefaultValue(defaults, thisParam-1);
  308. if (!def)
  309. {
  310. StringBuffer msg("Omitted parameter ");
  311. msg.append(parmno).append(" has no default value");
  312. reportError(errpos, ERR_PARAM_NODEFVALUE, "%s", msg.str());
  313. }
  314. else
  315. {
  316. if (!getFoldedConstantText(curParam, def))
  317. {
  318. StringBuffer msg("Default value for parameter ");
  319. msg.append(parmno).append(" should be a constant");
  320. reportError(errpos, ERR_PARAM_NODEFVALUE, "%s", msg.str());
  321. }
  322. }
  323. }
  324. //PrintLog("Set macro parm: %s", curParam.str());
  325. // if (macroParms->queryProp(formal->queryName()))
  326. // reportError(errpos, ERR_NAMED_ALREADY_HAS_VALUE, "Parameter %s already has a value supplied", argumentName->str());
  327. // else
  328. macroParms->setProp(formal->queryName()->str(), curParam.str());
  329. }
  330. curParam.clear();
  331. }
  332. /* This is pushing a macro definition. */
  333. void HqlLex::pushMacro(IHqlExpression *expr)
  334. {
  335. /* expr points to namedSymbol(no_funcdef):
  336. child(0)-> no_macro = macro body
  337. child(1) = parameters
  338. child(2) = defaults for parameters
  339. */
  340. YYSTYPE nextToken;
  341. int tok = yyLex(nextToken, false, 0);
  342. if (tok != '(')
  343. {
  344. //throw MakeStringException(2, "( expected");
  345. reportError(nextToken, ERR_EXPECTED_LEFTCURLY, "( expected");
  346. if (tok==EOF)
  347. return;
  348. // assume we've got an '(', we can continue parsing.
  349. }
  350. unsigned parenDepth = 1;
  351. StringBuffer curParam;
  352. Owned<IProperties> macroParms = createProperties();
  353. IHqlExpression * formals = expr->queryChild(1);
  354. IHqlExpression * defaults = expr->queryChild(2);
  355. unsigned formalParmCt = formals->numChildren();
  356. unsigned parmno = 0;
  357. IIdAtom * possibleName = NULL;
  358. IIdAtom * argumentName = NULL;
  359. while (parenDepth)
  360. {
  361. tok = yyLex(nextToken, false, 0);
  362. switch(tok)
  363. {
  364. case '[':
  365. case '(':
  366. parenDepth++;
  367. curParam.append((char)tok);
  368. break;
  369. case ']':
  370. if (parenDepth > 1)
  371. parenDepth--;
  372. curParam.append((char)tok);
  373. break;
  374. case ')':
  375. parenDepth--;
  376. if (parenDepth)
  377. curParam.append(')');
  378. else if (formalParmCt>0 || curParam.length()>0) // handle last parameter
  379. setMacroParam(nextToken, expr, curParam, argumentName, parmno, macroParms);
  380. break;
  381. case ',':
  382. if (parenDepth==1)
  383. setMacroParam(nextToken, expr, curParam, argumentName, parmno, macroParms);
  384. else
  385. curParam.append(',');
  386. possibleName = NULL;
  387. argumentName = NULL;
  388. break;
  389. case ASSIGN:
  390. {
  391. bool done = false;
  392. if (parenDepth == 1 && possibleName)
  393. {
  394. //Horrible. Allow NAMED <id> := or <id> :=
  395. const char * text = curParam.str();
  396. while (isspace((byte)*text)) text++;
  397. if (memicmp(text, "NAMED", 5) == 0)
  398. text += 5;
  399. while (isspace((byte)*text)) text++;
  400. if (strlen(possibleName->str()) == strlen(text))
  401. {
  402. argumentName = possibleName;
  403. possibleName = NULL;
  404. curParam.clear();
  405. done = true;
  406. }
  407. }
  408. if (!done)
  409. getTokenText(curParam.append(' '));
  410. break;
  411. }
  412. case EOF:
  413. reportError(nextToken, ERR_MACRO_EOFINPARAM,"EOF encountered while gathering macro parameters");
  414. // no attempt to recover at the end of the file, but cleanup is needed.
  415. return;
  416. case UNKNOWN_ID:
  417. possibleName = nextToken.getId();
  418. //fall through
  419. default:
  420. curParam.append(' ');
  421. getTokenText(curParam);
  422. break;
  423. }
  424. nextToken.release();
  425. }
  426. if (parmno > formalParmCt)
  427. {
  428. StringBuffer msg("Too many actual parameters supplied to macro");
  429. if (expr->queryName())
  430. msg.append(' ').append(expr->queryName());
  431. msg.appendf(": expected %d, given %d", formalParmCt, parmno);
  432. reportError(nextToken, ERR_PARAM_TOOMANY, "%s", msg.str());
  433. }
  434. else if (parmno < formalParmCt)
  435. {
  436. for (unsigned idx = parmno; idx < formalParmCt; idx++)
  437. {
  438. IHqlExpression* formal = formals->queryChild(idx);
  439. if (!macroParms->queryProp(formal->queryName()->str()))
  440. {
  441. IHqlExpression* def = queryDefaultValue(defaults, idx);
  442. if (def)
  443. {
  444. if (!getFoldedConstantText(curParam, def))
  445. {
  446. StringBuffer msg("Omitted parameter ");
  447. msg.append(idx+1);
  448. if (expr->queryName())
  449. msg.append(" to macro ").append(expr->queryName());
  450. msg.append(" should be a constant value");
  451. reportError(nextToken, ERR_PARAM_NODEFVALUE, "%s", msg.str());
  452. }
  453. macroParms->setProp(formal->queryName()->str(), curParam.str());
  454. //PrintLog("Set macro parm: %s", curParam.str());
  455. curParam.clear();
  456. }
  457. else
  458. {
  459. StringBuffer msg("Omitted parameter ");
  460. msg.append(idx+1);
  461. if (expr->queryName())
  462. msg.append(" to macro ").append(expr->queryName());
  463. msg.append(" has no default value");
  464. reportError(nextToken, ERR_PARAM_NODEFVALUE, "%s", msg.str());
  465. }
  466. }
  467. }
  468. }
  469. IHqlExpression *macroBodyExpr = expr->queryChild(0);
  470. IFileContents * macroContents = static_cast<IFileContents *>(macroBodyExpr->queryUnknownExtra());
  471. if (isMacroActive(expr))
  472. {
  473. StringBuffer msg;
  474. msg.append("recursive macro call: ").append(getMacroName());
  475. reportError(nextToken, ERR_MACRO_RECURSIVE, "%s", msg.str());
  476. // error recovery
  477. if (expr->isAction())
  478. pushText("0;");
  479. else if (expr->isDataset())
  480. pushText("{}");
  481. else
  482. pushText("0 ENDMACRO");
  483. }
  484. else
  485. {
  486. inmacro = new HqlLex(yyParser, macroContents, NULL, LINK(expr));
  487. #if defined(TRACE_MACRO)
  488. PrintLog("MACRO>> inmacro %p created for \"%s\" at %d:%d\n",inmacro, s.str(),macroBodyExpr->getStartLine(),macroBodyExpr->getStartColumn());
  489. // PrintLog("MACRO>> macro called at %d:%d\n", expr->getStartLine(),expr->getStartColumn());
  490. #endif
  491. /* set the lineno and column in the original source as the starting point */
  492. inmacro->yyLineNo = macroBodyExpr->getStartLine();
  493. inmacro->yyColumn = macroBodyExpr->getStartColumn();
  494. inmacro->setParentLex(this);
  495. inmacro->macroParms.setown(macroParms.getClear());
  496. }
  497. }
  498. /* Read encrypted syntax, and push the decrypted text as a macro. */
  499. void HqlLex::processEncrypted()
  500. {
  501. YYSTYPE nextToken;
  502. if (yyLex(nextToken, false,0) != '(')
  503. {
  504. reportError(nextToken, ERR_EXPECTED_LEFTCURLY, "( expected");
  505. nextToken.release();
  506. return;
  507. }
  508. StringBuffer encoded64;
  509. loop
  510. {
  511. if (yyLex(nextToken, false,0) != STRING_CONST)
  512. {
  513. reportError(nextToken, ERR_EXPECTED, "String expected");
  514. nextToken.release();
  515. return;
  516. }
  517. OwnedHqlExpr str = nextToken.getExpr();
  518. getStringValue(encoded64, str);
  519. int next = yyLex(nextToken, false,0);
  520. if (next == ')')
  521. break;
  522. if (next != ',')
  523. {
  524. reportError(nextToken, ERR_EXPECTED_COMMA, ", expected");
  525. nextToken.release();
  526. return;
  527. }
  528. }
  529. if (yyLex(nextToken, false,0) != ';')
  530. {
  531. reportError(nextToken, ERR_EXPECTED, "; expected");
  532. nextToken.release();
  533. return;
  534. }
  535. MemoryBuffer decrypted;
  536. decryptEclAttribute(decrypted, encoded64.str());
  537. decrypted.append(0); // add a null terminator to the string...
  538. Owned<ISourcePath> sourcePath = createSourcePath("<encrypted>");
  539. Owned<IFileContents> decryptedContents = createFileContentsFromText((const char *)decrypted.toByteArray(), sourcePath);
  540. inmacro = new HqlLex(yyParser, decryptedContents, NULL, NULL);
  541. inmacro->setParentLex(this);
  542. inmacro->encrypted = true;
  543. }
  544. /* Return: true if more parameter(s) left. */
  545. bool HqlLex::getParameter(StringBuffer &curParam, const char* for_what, int* startLine, int* startCol)
  546. {
  547. unsigned parenDepth = 1;
  548. if (startLine) *startLine = -1;
  549. YYSTYPE nextToken;
  550. for (;;)
  551. {
  552. int tok = yyLex(nextToken, false, 0);
  553. if (startLine && *startLine == -1)
  554. {
  555. *startLine = nextToken.pos.lineno;
  556. *startCol = nextToken.pos.column;
  557. }
  558. switch(tok)
  559. {
  560. case '(':
  561. case '[':
  562. parenDepth++;
  563. curParam.append((char) tok);
  564. break;
  565. case ')':
  566. if (parenDepth==1)
  567. return false;
  568. // fall into
  569. case ']':
  570. parenDepth--;
  571. curParam.append((char) tok);
  572. break;
  573. case ',':
  574. if (parenDepth==1)
  575. return true;
  576. curParam.append(',');
  577. break;
  578. case EOF:
  579. {
  580. StringBuffer msg("EOF encountered while gathering parameters for ");
  581. msg.append(for_what);
  582. reportError(nextToken, ERR_TMPLT_EOFINPARAM, "%s", msg.str());
  583. }
  584. return false;
  585. default:
  586. curParam.append(' ');
  587. getTokenText(curParam);
  588. break;
  589. }
  590. nextToken.release();
  591. }
  592. }
  593. void HqlLex::doIf(YYSTYPE & returnToken)
  594. {
  595. StringBuffer forwhat;
  596. int line = returnToken.pos.lineno, col = returnToken.pos.column;
  597. forwhat.appendf("#IF(%d,%d)",returnToken.pos.lineno,returnToken.pos.column);
  598. int tok = yyLex(returnToken, false, 0);
  599. if (tok != '(')
  600. reportError(returnToken, ERR_EXPECTED_LEFTCURLY, "( expected"); // MORE - make it fatal!
  601. StringBuffer curParam("(");
  602. if (getParameter(curParam, forwhat.str()))
  603. {
  604. reportError(returnToken, ERR_OPERANDS_TOOMANY, "too many operands");
  605. StringBuffer dummy;
  606. while (getParameter(dummy,forwhat.str()))
  607. ;
  608. }
  609. curParam.append(')');
  610. IValue *value = parseConstExpression(returnToken, curParam, queryTopXmlScope(),line,col);
  611. if (value && !value->getBoolValue())
  612. {
  613. skipping = 1;
  614. while (skipping)
  615. {
  616. int tok = yyLex(returnToken, false,0);
  617. returnToken.release();
  618. if (tok == EOF)
  619. {
  620. StringBuffer msg;
  621. msg.appendf("Unexpected EOF in %s: #END expected",forwhat.str());
  622. reportError(returnToken, ERR_TMPLT_HASHENDEXPECTED, "%s", msg.str());
  623. clearNestedHash(); // prevent unnecessary more error messages
  624. break;
  625. }
  626. }
  627. }
  628. ::Release(value);
  629. }
  630. int HqlLex::doElse(YYSTYPE & returnToken, bool lookup, const short * activeState, bool isElseIf)
  631. {
  632. StringBuffer forwhat;
  633. forwhat.appendf("#%s(%d,%d)",isElseIf ? "ELSEIF" : "ELSE", returnToken.pos.lineno,returnToken.pos.column);
  634. if ((hashendKinds.ordinality() == 0) || (hashendKinds.tos() != HashStmtIf))
  635. {
  636. reportError(returnToken, ERR_TMPLT_EXTRAELSE,"#ELSE does not match a #IF");
  637. return SKIPPED;
  638. }
  639. if (isElseIf)
  640. hashendDepths.append(hashendDepths.pop()+1);
  641. switch (skipping)
  642. {
  643. case 0:
  644. skipping = hashendDepths.tos();
  645. while (skipping)
  646. {
  647. int tok = yyLex(returnToken, lookup, activeState);
  648. returnToken.release();
  649. if (tok == EOF)
  650. {
  651. forwhat.insert(0,"Unexpected EOF in ").append(": #END expected");
  652. reportError(returnToken, ERR_TMPLT_HASHENDEXPECTED, "%s", forwhat.str());
  653. clearNestedHash(); // prevent unnecessary more error messages
  654. return tok;
  655. }
  656. }
  657. return yyLex(returnToken, lookup, activeState);
  658. case 1:
  659. skipping = 0;
  660. if (isElseIf)
  661. doIf(returnToken);
  662. return SKIPPED; // looks wrong, but called within a doIf() loop, and first return is ignored
  663. default:
  664. if (isElseIf)
  665. skipping++;
  666. return SKIPPED;
  667. }
  668. }
  669. void HqlLex::doDeclare(YYSTYPE & returnToken)
  670. {
  671. StringBuffer forwhat;
  672. forwhat.appendf("#DECLARE(%d,%d)",returnToken.pos.lineno,returnToken.pos.column);
  673. IIdAtom * name = NULL;
  674. if (yyLex(returnToken, false,0) != '(')
  675. {
  676. reportError(returnToken, ERR_EXPECTED_LEFTCURLY, "( expected");
  677. returnToken.release();
  678. return;
  679. }
  680. for (;;)
  681. {
  682. int tok = yyLex(returnToken, false,0);
  683. if (tok == EOF)
  684. {
  685. StringBuffer msg;
  686. msg.append("Unexpected EOF in ").append(forwhat.str()).append(": ')' expected");
  687. reportError(returnToken, ERR_TMPLT_HASHENDEXPECTED, "%s", msg.str());
  688. clearNestedHash(); // prevent unnecessary more error messages
  689. return;
  690. }
  691. if (tok != UNKNOWN_ID)
  692. {
  693. reportError(returnToken, ERR_EXPECTED_IDENTIFIER, "Identifier expected");
  694. returnToken.release();
  695. continue;
  696. }
  697. name = returnToken.getId();
  698. declareXmlSymbol(returnToken, name->getAtomNamePtr());
  699. tok = yyLex(returnToken, false,0);
  700. if (tok == ')')
  701. break;
  702. else if (tok == ',')
  703. continue;
  704. else if (tok == EOF)
  705. {
  706. StringBuffer msg;
  707. msg.append("Unexpected EOF in ").append(forwhat.str()).append(": ) expected");
  708. reportError(returnToken, ERR_TMPLT_HASHENDEXPECTED, "%s", msg.str());
  709. clearNestedHash(); // prevent unnecessary more error messages
  710. }
  711. else
  712. {
  713. reportError(returnToken, ERR_EXPECTED, "',' or ')' expected");
  714. returnToken.release();
  715. }
  716. }
  717. }
  718. void HqlLex::doExpand(YYSTYPE & returnToken)
  719. {
  720. StringBuffer forwhat;
  721. forwhat.appendf("#DECLARE(%d,%d)",returnToken.pos.lineno,returnToken.pos.column);
  722. if (yyLex(returnToken, false,0) != '(')
  723. {
  724. reportError(returnToken, ERR_EXPECTED_LEFTCURLY, "( expected");
  725. returnToken.release();
  726. return;
  727. }
  728. StringBuffer curParam("(");
  729. int startLine, startCol;
  730. if (getParameter(curParam,forwhat.str(),&startLine,&startCol))
  731. {
  732. reportError(returnToken, ERR_OPERANDS_TOOMANY, "Too many operands");
  733. StringBuffer dummy;
  734. while (getParameter(dummy,forwhat.str()))
  735. ;
  736. }
  737. curParam.append(')');
  738. Owned<IValue> value = parseConstExpression(returnToken, curParam, queryTopXmlScope(),startLine-1,startCol);
  739. if (value)
  740. {
  741. StringBuffer buf;
  742. value->getStringValue(buf);
  743. if (buf.length())
  744. pushText(buf.str());
  745. }
  746. }
  747. void HqlLex::doSet(YYSTYPE & returnToken, bool append)
  748. {
  749. StringBuffer forwhat;
  750. forwhat.appendf("%s(%d,%d)",append?"#APPEND":"#SET",returnToken.pos.lineno,returnToken.pos.column);
  751. IIdAtom * name = NULL;
  752. if (yyLex(returnToken, false,0) != '(')
  753. {
  754. reportError(returnToken, ERR_EXPECTED_LEFTCURLY, "( expected");
  755. returnToken.release();
  756. return;
  757. }
  758. if (yyLex(returnToken, false,0) != UNKNOWN_ID)
  759. {
  760. reportError(returnToken, ERR_EXPECTED_IDENTIFIER, "Identifier expected");
  761. returnToken.release();
  762. return;
  763. }
  764. name = returnToken.getId();
  765. if (yyLex(returnToken, false,0) != ',')
  766. {
  767. reportError(returnToken, ERR_EXPECTED_COMMA, ", expected");
  768. return;
  769. }
  770. StringBuffer curParam("(");
  771. int startLine, startCol;
  772. if (getParameter(curParam,forwhat.str(),&startLine,&startCol))
  773. {
  774. reportError(returnToken, ERR_OPERANDS_TOOMANY, "Too many operands");
  775. StringBuffer dummy;
  776. while (getParameter(dummy,forwhat.str()))
  777. ;
  778. }
  779. curParam.append(')');
  780. IValue *value = parseConstExpression(returnToken, curParam, queryTopXmlScope(),startLine-1,startCol);
  781. if (value)
  782. {
  783. StringBuffer buf;
  784. value->getStringValue(buf);
  785. setXmlSymbol(returnToken, name->getAtomNamePtr(), buf.str(), append);
  786. value->Release();
  787. }
  788. }
  789. void HqlLex::doLine(YYSTYPE & returnToken)
  790. {
  791. StringBuffer forwhat;
  792. int line = returnToken.pos.lineno, col = returnToken.pos.column;
  793. forwhat.appendf("LINE(%d,%d)",returnToken.pos.lineno,returnToken.pos.column);
  794. IIdAtom * name = NULL;
  795. if (yyLex(returnToken, false,0) != '(')
  796. {
  797. reportError(returnToken, ERR_EXPECTED_LEFTCURLY, "( expected");
  798. returnToken.release();
  799. return;
  800. }
  801. StringBuffer curParam("(");
  802. bool moreParams = getParameter(curParam, forwhat.str(), &line, &col);
  803. curParam.append(')');
  804. IValue *value = parseConstExpression(returnToken, curParam, queryTopXmlScope(),line,col);
  805. if (value && value->getTypeCode()==type_int)
  806. {
  807. returnToken.pos.lineno = yyLineNo = (int)value->getIntValue();
  808. }
  809. else
  810. reportError(returnToken, ERR_EXPECTED_CONST, "Constant integer expression expected");
  811. ::Release(value);
  812. if (moreParams)
  813. {
  814. int startLine, startCol;
  815. if (getParameter(curParam,forwhat.str(),&startLine,&startCol))
  816. {
  817. reportError(returnToken, ERR_OPERANDS_TOOMANY, "Too many operands");
  818. StringBuffer dummy;
  819. while (getParameter(dummy,forwhat.str()))
  820. ;
  821. }
  822. curParam.append(')');
  823. IValue *value = parseConstExpression(returnToken, curParam, queryTopXmlScope(),startLine-1,startCol);
  824. if (value && value->getTypeCode()==type_string)
  825. {
  826. StringBuffer buf;
  827. value->getStringValue(buf);
  828. // MORE - set filename here
  829. value->Release();
  830. }
  831. else
  832. reportError(returnToken, ERR_EXPECTED_CONST, "Constant string expression expected");
  833. }
  834. }
  835. void HqlLex::doError(YYSTYPE & returnToken, bool isError)
  836. {
  837. StringBuffer forwhat;
  838. forwhat.appendf("%s(%d,%d)",isError?"#ERROR":"#WARNING",returnToken.pos.lineno,returnToken.pos.column);
  839. IIdAtom * name = NULL;
  840. if (yyLex(returnToken, false,0) != '(')
  841. {
  842. reportError(returnToken, ERR_EXPECTED_LEFTCURLY, "( expected");
  843. returnToken.release();
  844. return;
  845. }
  846. StringBuffer curParam("(");
  847. int startLine, startCol;
  848. if (getParameter(curParam,forwhat.str(),&startLine,&startCol))
  849. {
  850. reportError(returnToken, ERR_OPERANDS_TOOMANY, "Too many operands");
  851. StringBuffer dummy;
  852. while (getParameter(dummy,forwhat.str()))
  853. ;
  854. }
  855. curParam.append(')');
  856. StringBuffer buf;
  857. OwnedIValue value = parseConstExpression(returnToken, curParam, queryTopXmlScope(),startLine-1,startCol);
  858. if (value)
  859. {
  860. value->getStringValue(buf);
  861. }
  862. else
  863. buf.append(curParam.length()-2, curParam.str()+1);
  864. if (isError)
  865. reportError(returnToken, ERR_HASHERROR, "#ERROR: %s", buf.str());
  866. else
  867. reportWarning(returnToken, WRN_HASHWARNING, "#WARNING: %s", buf.str());
  868. }
  869. void HqlLex::doExport(YYSTYPE & returnToken, bool toXml)
  870. {
  871. StringBuffer forwhat;
  872. forwhat.appendf("#EXPORT(%d,%d)",returnToken.pos.lineno,returnToken.pos.column);
  873. IIdAtom * exportname = NULL;
  874. if (yyLex(returnToken, false,0) != '(')
  875. {
  876. reportError(returnToken, ERR_EXPECTED_LEFTCURLY, "( expected");
  877. returnToken.release();
  878. return;
  879. }
  880. if (yyLex(returnToken, false,0) != UNKNOWN_ID)
  881. {
  882. reportError(returnToken, ERR_EXPECTED_IDENTIFIER, "Identifier expected");
  883. returnToken.release();
  884. return;
  885. }
  886. exportname = returnToken.getId();
  887. if (yyLex(returnToken, false,0) != ',')
  888. {
  889. reportError(returnToken, ERR_EXPECTED_COMMA, ", expected");
  890. return;
  891. }
  892. IPropertyTree *data = createPTree("Data", ipt_caseInsensitive);
  893. for (;;)
  894. {
  895. StringBuffer curParam("SIZEOF(");
  896. bool more = getParameter(curParam,"#EXPORT");
  897. curParam.append(",MAX)");
  898. OwnedHqlExpr expr;
  899. Owned<IHqlScope> scope = new CHqlParserPseduoScope(yyParser);
  900. try
  901. {
  902. HqlLookupContext ctx(yyParser->lookupCtx);
  903. Owned<IFileContents> exportContents = createFileContentsFromText(curParam.str(), sourcePath);
  904. expr.setown(parseQuery(scope, exportContents, ctx, xmlScope, NULL, true));
  905. if (expr && (expr->getOperator() == no_sizeof))
  906. {
  907. IHqlExpression * child = expr->queryChild(0);
  908. node_operator op = child->getOperator();
  909. if(op==no_table || op==no_usertable || op==no_newusertable || op == no_record || op == no_select || op == no_field)
  910. exportData(data, child, true);
  911. else if (child->queryRecord())
  912. exportData(data, child->queryRecord(), true);
  913. else
  914. reportError(returnToken, ERR_EXPECTED_COMMA, "DATASET or TABLE expression expected");
  915. }
  916. else
  917. reportError(returnToken, ERR_EXPECTED_COMMA, "Could not parse the argument passed to #EXPORT");
  918. }
  919. catch (...)
  920. {
  921. setXmlSymbol(returnToken, exportname->getAtomNamePtr(), "", false);
  922. PrintLog("Unexpected exception in doExport()");
  923. }
  924. if (!more)
  925. break;
  926. }
  927. StringBuffer buf;
  928. toXML(data, buf, 0);
  929. if (toXml)
  930. ensureTopXmlScope(returnToken)->loadXML(buf.str(), exportname->getAtomNamePtr());
  931. else
  932. setXmlSymbol(returnToken, exportname->getAtomNamePtr(), buf.str(), false);
  933. data->Release();
  934. }
  935. void HqlLex::doTrace(YYSTYPE & returnToken)
  936. {
  937. StringBuffer forwhat;
  938. forwhat.appendf("#TRACE(%d,%d)",returnToken.pos.lineno,returnToken.pos.column);
  939. IIdAtom * name = NULL;
  940. if (yyLex(returnToken, false,0) != '(')
  941. {
  942. reportError(returnToken, ERR_EXPECTED_LEFTCURLY, "( expected");
  943. returnToken.release();
  944. return;
  945. }
  946. StringBuffer curParam("(");
  947. int startLine, startCol;
  948. if (getParameter(curParam,forwhat.str(),&startLine,&startCol))
  949. {
  950. reportError(returnToken, ERR_OPERANDS_TOOMANY, "Too many operands");
  951. StringBuffer dummy;
  952. while (getParameter(dummy,forwhat.str()))
  953. ;
  954. }
  955. curParam.append(')');
  956. Owned<IValue> value = parseConstExpression(returnToken, curParam, queryTopXmlScope(),startLine-1,startCol);
  957. if (value)
  958. {
  959. StringBuffer buf;
  960. value->getStringValue(buf);
  961. FILE *trace = fopen("hql.log", "at");
  962. if (trace)
  963. {
  964. fwrite(buf.str(),buf.length(),1,trace);
  965. fclose(trace);
  966. }
  967. }
  968. }
  969. void HqlLex::doFor(YYSTYPE & returnToken, bool doAll)
  970. {
  971. //MTIME_SECTION(timer, "HqlLex::doFor")
  972. int startLine = -1, startCol = 0;
  973. StringBuffer forwhat;
  974. forwhat.appendf("#FOR(%d,%d)",returnToken.pos.lineno,returnToken.pos.column);
  975. IIdAtom * name = NULL;
  976. if (yyLex(returnToken, false,0) != '(')
  977. {
  978. reportError(returnToken, ERR_EXPECTED_LEFTCURLY, "( expected");
  979. returnToken.release();
  980. return;
  981. }
  982. if (yyLex(returnToken, false,0) != UNKNOWN_ID)
  983. {
  984. reportError(returnToken, ERR_EXPECTED_IDENTIFIER, "Identifier expected");
  985. returnToken.release();
  986. return;
  987. }
  988. name = returnToken.getId();
  989. forFilter.clear();
  990. // Note - we gather the for filter and body in skip mode (deferring evaluation of #if etc) since the context will be different each time...
  991. skipping = 1;
  992. int tok = yyLex(returnToken, false,0);
  993. if (tok == '(')
  994. {
  995. forFilter.append('(');
  996. while (getParameter(forFilter, forwhat.str()))
  997. forFilter.append(") AND (");
  998. forFilter.append(')');
  999. tok = yyLex(returnToken, false,0);
  1000. }
  1001. if (tok != ')')
  1002. {
  1003. reportError(returnToken, ERR_EXPECTED_RIGHTCURLY, ") expected");
  1004. // recovery: assume a ')' is here. And push back the token.
  1005. pushText(get_yyText());
  1006. returnToken.release();
  1007. }
  1008. // Now gather the tokens we are going to repeat...
  1009. forBody.clear();
  1010. for (;;)
  1011. {
  1012. int tok = yyLex(returnToken, false,0);
  1013. if (startLine == -1)
  1014. {
  1015. startLine = returnToken.pos.lineno - 1;
  1016. startCol = returnToken.pos.column;
  1017. }
  1018. if (tok == EOF)
  1019. {
  1020. reportError(returnToken, ERR_TMPLT_HASHENDEXPECTED, "EOF encountered inside %s: #END expected", forwhat.str());
  1021. clearNestedHash(); // prevent unnecessary more error messages
  1022. return;
  1023. }
  1024. if (tok == HASHEND && !skipping)
  1025. break;
  1026. forBody.append(' ');
  1027. getTokenText(forBody);
  1028. returnToken.release();
  1029. }
  1030. ::Release(forLoop);
  1031. forLoop = getSubScopes(returnToken, name->getAtomNamePtr(), doAll);
  1032. loopTimes = 0;
  1033. if (forLoop && forLoop->first()) // more - check filter
  1034. checkNextLoop(returnToken, true, startLine, startCol);
  1035. }
  1036. void HqlLex::doLoop(YYSTYPE & returnToken)
  1037. {
  1038. int startLine = -1, startCol = 0;
  1039. StringBuffer forwhat;
  1040. forwhat.appendf("#LOOP(%d,%d)",returnToken.pos.lineno,returnToken.pos.column);
  1041. // Now gather the tokens we are going to repeat...
  1042. forBody.clear();
  1043. // Note - we gather the for filter and body in skip mode (deferring evaluation of #if etc) since the context will be different each time...
  1044. skipping = 1;
  1045. hasHashbreak = false;
  1046. for (;;)
  1047. {
  1048. int tok = yyLex(returnToken, false,0);
  1049. if (startLine == -1)
  1050. {
  1051. startLine = returnToken.pos.lineno-1;
  1052. startCol = returnToken.pos.column;
  1053. }
  1054. if (tok == EOF)
  1055. {
  1056. reportError(returnToken, ERR_TMPLT_HASHENDEXPECTED, "EOF encountered inside %s: #END expected",forwhat.str());
  1057. clearNestedHash(); // prevent unnecessary more error messages
  1058. return;
  1059. }
  1060. if (tok == HASHEND && !skipping)
  1061. break;
  1062. forBody.append(' ');
  1063. getTokenText(forBody);
  1064. returnToken.release();
  1065. }
  1066. if (!hasHashbreak)
  1067. {
  1068. reportError(returnToken, ERR_TMPLT_NOBREAKINLOOP,"No #BREAK inside %s: infinite loop will occur", forwhat.str());
  1069. return;
  1070. }
  1071. ::Release(forLoop);
  1072. forLoop = new CDummyScopeIterator(ensureTopXmlScope(returnToken));
  1073. forFilter.clear();
  1074. loopTimes = 0;
  1075. if (forLoop->first()) // more - check filter
  1076. checkNextLoop(returnToken, true,startLine,startCol);
  1077. }
  1078. void HqlLex::doGetDataType(YYSTYPE & returnToken)
  1079. {
  1080. int tok = yyLex(returnToken, false,0);
  1081. if (tok != '(')
  1082. reportError(returnToken, ERR_EXPECTED_LEFTCURLY, "( expected"); // MORE - make it fatal!
  1083. StringBuffer curParam("(");
  1084. if (getParameter(curParam, "#GETDATATYPE"))
  1085. {
  1086. reportError(returnToken, ERR_OPERANDS_TOOMANY, "too many operands");
  1087. StringBuffer dummy;
  1088. while (getParameter(dummy,"#GETDATATYPE"))
  1089. ;
  1090. }
  1091. curParam.append(')');
  1092. StringBuffer type;
  1093. doGetDataType(type, curParam.str(), returnToken.pos.lineno, returnToken.pos.column);
  1094. pushText(type.str());
  1095. }
  1096. StringBuffer& HqlLex::doGetDataType(StringBuffer & type, const char * text, int lineno, int column)
  1097. {
  1098. OwnedHqlExpr expr = parseECL(text, queryTopXmlScope(), lineno, column);
  1099. if(expr)
  1100. {
  1101. type.append('\'');
  1102. if (expr->queryType())
  1103. expr->queryType()->getECLType(type);
  1104. type.append('\'');
  1105. }
  1106. else
  1107. type.append("'unknown_type'");
  1108. return type;
  1109. }
  1110. int HqlLex::doHashText(YYSTYPE & returnToken)
  1111. {
  1112. StringBuffer forwhat;
  1113. forwhat.appendf("#TEXT(%d,%d)",returnToken.pos.lineno,returnToken.pos.column);
  1114. if (yyLex(returnToken, false,0) != '(')
  1115. {
  1116. reportError(returnToken, ERR_EXPECTED_LEFTCURLY, "( expected");
  1117. returnToken.release();
  1118. returnToken.setExpr(createConstant(""));
  1119. return STRING_CONST;
  1120. }
  1121. StringBuffer parameterText;
  1122. bool moreParams = getParameter(parameterText, forwhat.str());
  1123. if (!moreParams)
  1124. {
  1125. while (parameterText.length() && parameterText.charAt(0)==' ')
  1126. parameterText.remove(0, 1);
  1127. }
  1128. else
  1129. {
  1130. reportError(returnToken, ERR_OPERANDS_TOOMANY, "Too many operands");
  1131. StringBuffer dummy;
  1132. while (getParameter(dummy,forwhat.str()))
  1133. ;
  1134. }
  1135. returnToken.setExpr(createConstant(parameterText));
  1136. return (STRING_CONST);
  1137. }
  1138. void HqlLex::doInModule(YYSTYPE & returnToken)
  1139. {
  1140. #ifdef TIMING_DEBUG
  1141. MTIME_SECTION(timer, "HqlLex::doInModule");
  1142. #endif
  1143. int tok = yyLex(returnToken, false,0);
  1144. if (tok != '(')
  1145. reportError(returnToken, ERR_EXPECTED_LEFTCURLY, "( expected");
  1146. StringBuffer moduleName, attrName;
  1147. if (getParameter(moduleName,"#INMODULE"))
  1148. {
  1149. if (getParameter(attrName,"#INMODULE"))
  1150. {
  1151. reportError(returnToken, ERR_OPERANDS_TOOMANY, "too many operands");
  1152. /* skip the rest */
  1153. StringBuffer dummy;
  1154. while (getParameter(dummy,"#INMODULE"))
  1155. ;
  1156. }
  1157. }
  1158. else
  1159. {
  1160. reportError(returnToken, ERR_PARAM_TOOFEW,"Too few parameters: #INMODULE needs 2");
  1161. /* recovery */
  1162. pushText("true");
  1163. return;
  1164. }
  1165. if (isInModule(yyParser->lookupCtx, moduleName.str(),attrName.str()))
  1166. pushText("true");
  1167. else
  1168. pushText("false");
  1169. }
  1170. static bool isInModule(HqlLookupContext & ctx, const char* moduleName, const char* attrName)
  1171. {
  1172. if (!ctx.queryRepository())
  1173. return false;
  1174. try
  1175. {
  1176. //hack: get rid of the extra leading spaces
  1177. const char* pModule = moduleName;
  1178. while(*pModule==' ') pModule++;
  1179. const char* pAttr = attrName;
  1180. while(*pAttr==' ') pAttr++;
  1181. OwnedHqlExpr match = ctx.queryRepository()->queryRootScope()->lookupSymbol(createIdAtom(pModule), LSFpublic, ctx);
  1182. IHqlScope * scope = match ? match->queryScope() : NULL;
  1183. if (scope)
  1184. {
  1185. OwnedHqlExpr expr = scope->lookupSymbol(createIdAtom(pAttr), LSFpublic, ctx);
  1186. if (expr)
  1187. return true;
  1188. }
  1189. }
  1190. catch (...)
  1191. {
  1192. PrintLog("Unexpected exception in doInModule()");
  1193. }
  1194. return false;
  1195. }
  1196. void HqlLex::doUniqueName(YYSTYPE & returnToken)
  1197. {
  1198. int tok = yyLex(returnToken, false,0);
  1199. if (tok != '(')
  1200. reportError(returnToken, ERR_EXPECTED_LEFTCURLY, "( expected");
  1201. else
  1202. tok = yyLex(returnToken, false,0);
  1203. if (tok != UNKNOWN_ID)
  1204. {
  1205. reportError(returnToken, ERR_EXPECTED_IDENTIFIER, "Identifier expected");
  1206. returnToken.release();
  1207. }
  1208. else
  1209. {
  1210. IIdAtom * name = returnToken.getId();
  1211. StringAttr pattern("__#__$__");
  1212. tok = yyLex(returnToken, false,0);
  1213. if (tok == ',')
  1214. {
  1215. tok = yyLex(returnToken, false,0);
  1216. if (tok == STRING_CONST)
  1217. {
  1218. StringBuffer text;
  1219. OwnedHqlExpr str = returnToken.getExpr();
  1220. getStringValue(text, str);
  1221. pattern.set(text.str());
  1222. tok = yyLex(returnToken, false,0);
  1223. }
  1224. else
  1225. reportError(returnToken, ERR_EXPECTED, "string expected");
  1226. }
  1227. declareUniqueName(name->getAtomNamePtr(), pattern);
  1228. }
  1229. if (tok != ')')
  1230. reportError(returnToken, ERR_EXPECTED_RIGHTCURLY, ") expected");
  1231. }
  1232. static int gUniqueId = 0;
  1233. void resetLexerUniqueNames() { gUniqueId = 0; }
  1234. void HqlLex::declareUniqueName(const char *name, const char * pattern)
  1235. {
  1236. IXmlScope *top = queryTopXmlScope();
  1237. if (!top)
  1238. top = xmlScope = createXMLScope();
  1239. StringBuffer value;
  1240. if (!top->getValue(name,value))
  1241. top->declareValue(name);
  1242. StringBuffer uniqueName;
  1243. bool added = false;
  1244. for (const char * cur = pattern; *cur; cur++)
  1245. {
  1246. char next = *cur;
  1247. switch (next)
  1248. {
  1249. case '#':
  1250. uniqueName.append(name);
  1251. break;
  1252. case '$':
  1253. uniqueName.append(++gUniqueId);
  1254. added = true;
  1255. break;
  1256. default:
  1257. uniqueName.append(next);
  1258. break;
  1259. }
  1260. }
  1261. if (!added)
  1262. uniqueName.append(++gUniqueId);
  1263. //PrintLog("Declaring unique name: %s",uniqueName.str());
  1264. top->setValue(name,uniqueName.str());
  1265. }
  1266. void HqlLex::doIsValid(YYSTYPE & returnToken)
  1267. {
  1268. int tok = yyLex(returnToken, false,0);
  1269. if (tok != '(')
  1270. reportError(returnToken, ERR_EXPECTED_LEFTCURLY, "( expected");
  1271. StringBuffer curParam("(");
  1272. if (getParameter(curParam,"#ISVALID"))
  1273. {
  1274. reportError(returnToken, ERR_OPERANDS_TOOMANY, "too many operands");
  1275. StringBuffer dummy;
  1276. while (getParameter(dummy,"#ISVALID"))
  1277. ;
  1278. }
  1279. curParam.append(')');
  1280. IHqlExpression * expr = NULL;
  1281. IHqlScope *scope = createScope();
  1282. try
  1283. {
  1284. HqlLookupContext ctx(yyParser->lookupCtx);
  1285. ctx.errs.clear(); //Deliberately ignore any errors
  1286. Owned<IFileContents> contents = createFileContentsFromText(curParam.str(), sourcePath);
  1287. expr = parseQuery(scope, contents, ctx, xmlScope, NULL, true);
  1288. if(expr)
  1289. {
  1290. pushText("true");
  1291. }
  1292. else
  1293. {
  1294. pushText("false");
  1295. }
  1296. }
  1297. catch (...)
  1298. {
  1299. pushText("false");
  1300. PrintLog("Unexpected exception in doIsValid()");
  1301. }
  1302. ::Release(expr);
  1303. ::Release(closeScope(scope));
  1304. }
  1305. void HqlLex::checkNextLoop(const YYSTYPE & errpos, bool first, int startLine, int startCol)
  1306. {
  1307. if (loopTimes++ > MAX_LOOP_TIMES)
  1308. {
  1309. reportError(errpos, ERR_TMPLT_LOOPEXCESSMAX,"The loop exceeded the limit: infinite loop is suspected");
  1310. return;
  1311. }
  1312. //printf("%d\r",loopTimes);
  1313. //assertex(forLoop);
  1314. while (first || forLoop->next())
  1315. {
  1316. bool filtered;
  1317. IXmlScope *subscope = (IXmlScope *) &forLoop->query();
  1318. if (forFilter.length())
  1319. {
  1320. #ifdef TIMING_DEBUG
  1321. MTIME_SECTION(timer, "HqlLex::checkNextLoopcond");
  1322. #endif
  1323. IValue *value = parseConstExpression(errpos, forFilter, subscope,startLine,startCol);
  1324. filtered = !value || !value->getBoolValue();
  1325. ::Release(value);
  1326. }
  1327. else
  1328. filtered = false;
  1329. if (!filtered)
  1330. {
  1331. pushText(forBody.str(),startLine,startCol);
  1332. inmacro->xmlScope = LINK(subscope);
  1333. return;
  1334. }
  1335. first = false;
  1336. }
  1337. forLoop->Release();
  1338. forLoop = NULL;
  1339. }
  1340. void HqlLex::doPreprocessorLookup(const YYSTYPE & errpos, bool stringify, int extra)
  1341. {
  1342. StringBuffer out;
  1343. char *text = get_yyText() + 1;
  1344. unsigned len = (size32_t)strlen(text) - 1;
  1345. text += extra;
  1346. len -= (extra+extra);
  1347. StringBuffer in;
  1348. in.append(len, text);
  1349. lookupXmlSymbol(errpos, in.str(), out);
  1350. if (stringify)
  1351. {
  1352. char *expanded = (char *) malloc(out.length()*2 + 3); // maximum it could be (might be a bit big for alloca)
  1353. char *s = expanded;
  1354. *s++='\'';
  1355. const char *finger = out.str();
  1356. for (;;)
  1357. {
  1358. char c = *finger++;
  1359. if (!c)
  1360. break;
  1361. switch(c)
  1362. {
  1363. case '\r':
  1364. *s++='\\'; *s++ ='r';
  1365. break;
  1366. case '\n':
  1367. *s++='\\'; *s++ ='n';
  1368. break;
  1369. case '\\':
  1370. case '\'':
  1371. *s++='\\';
  1372. // fall into
  1373. default:
  1374. *s++=c;
  1375. }
  1376. }
  1377. *s++ = '\'';
  1378. *s = '\0';
  1379. pushText(expanded);
  1380. free(expanded);
  1381. }
  1382. else
  1383. {
  1384. // a space is needed sometimes, e.g, #IF(true or %x%=2)
  1385. out.trim();
  1386. if (out.length())
  1387. {
  1388. out.insert(0," ");
  1389. pushText(out.str());
  1390. }
  1391. else
  1392. pushText(" 0");
  1393. }
  1394. }
  1395. //Read the text of a parameter, but also have a good guess at whether it is defined.
  1396. bool HqlLex::getDefinedParameter(StringBuffer &curParam, YYSTYPE & returnToken, const char* for_what, SharedHqlExpr & resolved)
  1397. {
  1398. enum { StateStart, StateDot, StateSelectId, StateFailed } state = StateStart;
  1399. unsigned parenDepth = 1;
  1400. OwnedHqlExpr expr;
  1401. for (;;)
  1402. {
  1403. int tok = yyLex(returnToken, false, 0);
  1404. switch(tok)
  1405. {
  1406. case '(':
  1407. case '[':
  1408. parenDepth++;
  1409. break;
  1410. case ')':
  1411. if (parenDepth-- == 1)
  1412. {
  1413. if (state == StateDot)
  1414. resolved.setown(expr.getClear());
  1415. return false;
  1416. }
  1417. break;
  1418. case ']':
  1419. parenDepth--;
  1420. break;
  1421. case ',':
  1422. if (parenDepth==1)
  1423. {
  1424. if (state == StateDot)
  1425. resolved.setown(expr.getClear());
  1426. return true;
  1427. }
  1428. break;
  1429. case EOF:
  1430. {
  1431. StringBuffer msg("EOF encountered while gathering parameters for ");
  1432. msg.append(for_what);
  1433. reportError(returnToken, ERR_TMPLT_EOFINPARAM, "%s", msg.str());
  1434. }
  1435. return false;
  1436. case UNKNOWN_ID:
  1437. if (parenDepth == 1)
  1438. {
  1439. switch (state)
  1440. {
  1441. case StateStart:
  1442. {
  1443. expr.setown(lookupSymbol(returnToken.getId(), returnToken));
  1444. state = expr ? StateDot : StateFailed;
  1445. break;
  1446. }
  1447. case StateDot:
  1448. {
  1449. state = StateFailed;
  1450. break;
  1451. }
  1452. case StateSelectId:
  1453. {
  1454. state = StateFailed;
  1455. if (expr->getOperator() == no_funcdef)
  1456. expr.set(expr->queryChild(0));
  1457. IHqlScope * scope = expr->queryScope();
  1458. if (scope)
  1459. {
  1460. expr.setown(yyParser->lookupSymbol(scope, returnToken.getId()));
  1461. if (expr)
  1462. state = StateDot;
  1463. }
  1464. break;
  1465. }
  1466. }
  1467. }
  1468. curParam.append(' ');
  1469. break;
  1470. case '.':
  1471. if (parenDepth == 1)
  1472. {
  1473. if (state == StateDot)
  1474. state = StateSelectId;
  1475. else
  1476. state = StateFailed;
  1477. }
  1478. break;
  1479. default:
  1480. curParam.append(' ');
  1481. break;
  1482. }
  1483. getTokenText(curParam);
  1484. returnToken.release();
  1485. }
  1486. }
  1487. bool HqlLex::doIsDefined(YYSTYPE & returnToken)
  1488. {
  1489. StringBuffer forwhat;
  1490. forwhat.appendf("#ISDEFINED(%d,%d)",returnToken.pos.lineno,returnToken.pos.column);
  1491. if (!assertNextOpenBra())
  1492. return false;
  1493. OwnedHqlExpr resolved;
  1494. StringBuffer paramText;
  1495. bool hasMore = getDefinedParameter(paramText, returnToken, forwhat.str(), resolved);
  1496. if (hasMore)
  1497. reportError(returnToken, ERR_EXPECTED, "Expected ')'");
  1498. return resolved != NULL;
  1499. }
  1500. void HqlLex::doDefined(YYSTYPE & returnToken)
  1501. {
  1502. StringBuffer forwhat;
  1503. forwhat.appendf("#DEFINED(%d,%d)",returnToken.pos.lineno,returnToken.pos.column);
  1504. if (!assertNextOpenBra())
  1505. return;
  1506. OwnedHqlExpr resolved;
  1507. StringBuffer param1Text;
  1508. StringBuffer param2Text;
  1509. bool hasMore = getDefinedParameter(param1Text, returnToken, forwhat.str(), resolved);
  1510. if (hasMore)
  1511. hasMore = getParameter(param2Text, forwhat.str());
  1512. if (hasMore)
  1513. reportError(returnToken, ERR_EXPECTED, "Expected ')'");
  1514. if (resolved)
  1515. pushText(param1Text);
  1516. else if (param2Text.length())
  1517. pushText(param2Text);
  1518. }
  1519. IHqlExpression *HqlLex::parseECL(const char * text, IXmlScope *xmlScope, int startLine, int startCol)
  1520. {
  1521. #ifdef TIMING_DEBUG
  1522. MTIME_SECTION(timer, "HqlLex::parseConstExpression");
  1523. #endif
  1524. // Use an ECL reserved word as the scope name to avoid name conflicts with these defined localscope.
  1525. Owned<IHqlScope> scope = new CHqlMultiParentScope(sharedId,yyParser->queryPrimaryScope(false),yyParser->queryPrimaryScope(true),yyParser->parseScope.get(),NULL);
  1526. HqlGramCtx parentContext(yyParser->lookupCtx);
  1527. yyParser->saveContext(parentContext, false);
  1528. Owned<IFileContents> contents = createFileContentsFromText(text, querySourcePath());
  1529. HqlGram parser(parentContext, scope, contents, xmlScope, true);
  1530. parser.getLexer()->set_yyLineNo(startLine);
  1531. parser.getLexer()->set_yyColumn(startCol);
  1532. return parser.yyParse(false, false);
  1533. }
  1534. IValue *HqlLex::parseConstExpression(const YYSTYPE & errpos, StringBuffer &curParam, IXmlScope *xmlScope, int startLine, int startCol)
  1535. {
  1536. #ifdef TIMING_DEBUG
  1537. MTIME_SECTION(timer, "HqlLex::parseConstExpression");
  1538. #endif
  1539. OwnedHqlExpr expr = parseECL(curParam, xmlScope, startLine, startCol);
  1540. OwnedIValue value;
  1541. if (expr)
  1542. {
  1543. try
  1544. {
  1545. CTemplateContext context(this, yyParser->lookupCtx, xmlScope, startLine, startCol);
  1546. OwnedHqlExpr folded = foldHqlExpression(expr, &context, HFOthrowerror|HFOfoldimpure|HFOforcefold);
  1547. if (folded)
  1548. {
  1549. if (folded->queryValue())
  1550. value.set(folded->queryValue());
  1551. }
  1552. }
  1553. catch (IException* except)
  1554. {
  1555. StringBuffer s;
  1556. reportError(errpos, except->errorCode(), "%s", except->errorMessage(s).str());
  1557. except->Release();
  1558. }
  1559. }
  1560. if (!value.get())
  1561. reportError(errpos, ERR_EXPECTED_CONST, "Constant expression expected"); // errpos could be better
  1562. return value.getClear();
  1563. }
  1564. int hexchar(char c)
  1565. {
  1566. if (c >= 'A' && c <= 'F')
  1567. return c - 'A' + 10;
  1568. else if (c >= 'a' && c <= 'f')
  1569. return c - 'a' + 10;
  1570. else
  1571. return c - '0';
  1572. }
  1573. void HqlLex::doApply(YYSTYPE & returnToken)
  1574. {
  1575. int tok = yyLex(returnToken, false,0);
  1576. int line = returnToken.pos.lineno, col = returnToken.pos.column;
  1577. if (tok != '(')
  1578. reportError(returnToken, ERR_EXPECTED_LEFTCURLY, "( expected"); // MORE - make it fatal!
  1579. StringBuffer curParam("(");
  1580. if (getParameter(curParam, "#APPLY"))
  1581. {
  1582. reportError(returnToken, ERR_OPERANDS_TOOMANY, "too many operands");
  1583. StringBuffer dummy;
  1584. while (getParameter(dummy, "#APPLY"))
  1585. ;
  1586. }
  1587. curParam.append(')');
  1588. OwnedHqlExpr actions = parseECL(curParam, queryTopXmlScope(), line, col);
  1589. if (actions)
  1590. {
  1591. CTemplateContext context(this, yyParser->lookupCtx, xmlScope,line,col);
  1592. OwnedHqlExpr folded = foldHqlExpression(actions, &context, HFOthrowerror|HFOfoldimpure|HFOforcefold);
  1593. }
  1594. else
  1595. reportError(returnToken, ERR_EXPECTED_CONST, "Constant expression expected");
  1596. }
  1597. void HqlLex::doMangle(YYSTYPE & returnToken, bool de)
  1598. {
  1599. int tok = yyLex(returnToken, false,0);
  1600. int line = returnToken.pos.lineno, col = returnToken.pos.column;
  1601. if (tok != '(')
  1602. reportError(returnToken, ERR_EXPECTED_LEFTCURLY, "( expected"); // MORE - make it fatal!
  1603. StringBuffer curParam("(");
  1604. if (getParameter(curParam, de?"#DEMANGLE":"#MANGLE"))
  1605. {
  1606. reportError(returnToken, ERR_OPERANDS_TOOMANY, "too many operands");
  1607. StringBuffer dummy;
  1608. while (getParameter(dummy, de?"#DEMANGLE":"MANGLE"))
  1609. ;
  1610. }
  1611. curParam.append(')');
  1612. IValue *value = parseConstExpression(returnToken, curParam, queryTopXmlScope(), line, col);
  1613. if (value)
  1614. {
  1615. const char *str = value->getStringValue(curParam.clear());
  1616. value->Release();
  1617. StringBuffer mangled;
  1618. mangle(yyParser->errorHandler,str,mangled,de);
  1619. pushText(mangled.str());
  1620. }
  1621. else
  1622. reportError(returnToken, ERR_EXPECTED_CONST, "Constant expression expected");
  1623. }
  1624. static StringBuffer& mangle(IErrorReceiver* errReceiver,const char* src, StringBuffer& mangled,bool de)
  1625. {
  1626. mangled.append("'");
  1627. for (const char *finger = src; *finger!=0; finger++)
  1628. {
  1629. unsigned char c = *finger;
  1630. if (isalnum(c))
  1631. {
  1632. if (finger == src && isdigit(c)) // a leading digit
  1633. {
  1634. if (de)
  1635. {
  1636. //errReceiver->reportError(returnToken, ERR_EXPECTED_CONST, "Bad parameter to #DEMANGLE", "CppTemplate");
  1637. PrintLog("Bad parameter to #DEMANGLE");
  1638. break;
  1639. }
  1640. else
  1641. mangled.appendf("_%02x",(int)c);
  1642. }
  1643. else
  1644. mangled.append(c);
  1645. }
  1646. else if (de)
  1647. {
  1648. if (c != '_')
  1649. {
  1650. //errReceiver->reportError(returnToken, ERR_EXPECTED_CONST, "Bad parameter to #DEMANGLE");
  1651. PrintLog("Bad parameter to #DEMANGLE");
  1652. break;
  1653. }
  1654. c = hexchar(finger[1])*16 + hexchar(finger[2]);
  1655. finger += 2;
  1656. if (c=='\'')
  1657. mangled.append('\\');
  1658. mangled.append(c);
  1659. }
  1660. else
  1661. mangled.appendf("_%02x", (int) c);
  1662. }
  1663. mangled.append('\'');
  1664. return mangled;
  1665. }
  1666. bool HqlLex::checkUnicodeLiteral(char const * str, unsigned length, unsigned & ep, StringBuffer & msg)
  1667. {
  1668. unsigned i;
  1669. for(i = 0; i < length; i++)
  1670. {
  1671. if (str[i] == '\\')
  1672. {
  1673. unsigned char next = str[++i];
  1674. if (next == '\'' || next == '\\' || next == 'n' || next == 'r' || next == 't' || next == 'a' || next == 'b' || next == 'f' || next == 'v' || next == '?' || next == '"')
  1675. {
  1676. continue;
  1677. }
  1678. else if (isdigit(next) && next < '8')
  1679. {
  1680. unsigned count;
  1681. for(count = 1; count < 3; count++)
  1682. {
  1683. next = str[++i];
  1684. if(!isdigit(next) || next >= '8')
  1685. {
  1686. msg.append("3-digit numeric escape sequence contained non-octal digit: ").append(next);
  1687. ep = i;
  1688. return false;
  1689. }
  1690. }
  1691. }
  1692. else if (next == 'u' || next == 'U')
  1693. {
  1694. unsigned count;
  1695. unsigned max = (next == 'u') ? 4 : 8;
  1696. for(count = 0; count < max; count++)
  1697. {
  1698. next = str[++i];
  1699. if(!isdigit(next) && (!isalpha(next) || tolower(next) > 'f'))
  1700. {
  1701. msg.append((max == 4) ? '4' : '8').append("-digit unicode escape sequence contained non-hex digit: ").append(next);
  1702. ep = i;
  1703. return false;
  1704. }
  1705. }
  1706. }
  1707. else
  1708. {
  1709. msg.append("Unrecognized escape sequence: ").append("\\").append(next);
  1710. ep = i;
  1711. return false;
  1712. }
  1713. }
  1714. }
  1715. return true;
  1716. }
  1717. //====================================== Error Reporting ======================================
  1718. bool HqlLex::isAborting()
  1719. {
  1720. return yyParser->isAborting();
  1721. }
  1722. void HqlLex::reportError(const YYSTYPE & returnToken, int errNo, const char *format, ...)
  1723. {
  1724. if (yyParser)
  1725. {
  1726. va_list args;
  1727. va_start(args, format);
  1728. yyParser->reportErrorVa(errNo, returnToken.pos, format, args);
  1729. va_end(args);
  1730. }
  1731. }
  1732. void HqlLex::reportWarning(const YYSTYPE & returnToken, int warnNo, const char *format, ...)
  1733. {
  1734. if (yyParser)
  1735. {
  1736. va_list args;
  1737. va_start(args, format);
  1738. yyParser->reportWarningVa(warnNo, returnToken, format, args);
  1739. va_end(args);
  1740. }
  1741. }
  1742. //====================================== XML DB =============================================
  1743. IXmlScope *HqlLex::queryTopXmlScope()
  1744. {
  1745. IXmlScope *top = NULL;
  1746. HqlLex *inlex = this;
  1747. while (inlex->inmacro)
  1748. inlex = inlex->inmacro;
  1749. while (inlex && !top)
  1750. {
  1751. top = inlex->xmlScope;
  1752. inlex = inlex->parentLex;
  1753. }
  1754. return top;
  1755. }
  1756. IXmlScope *HqlLex::ensureTopXmlScope(const YYSTYPE & errpos)
  1757. {
  1758. IXmlScope *top = queryTopXmlScope();
  1759. if (!top)
  1760. {
  1761. reportError(errpos, ERR_XML_NOSCOPE, "No XML scope active");
  1762. // recovery: create a default XML scope
  1763. top = xmlScope = ::loadXML("<xml></xml>");
  1764. }
  1765. return top;
  1766. }
  1767. StringBuffer &HqlLex::lookupXmlSymbol(const YYSTYPE & errpos, const char *name, StringBuffer &ret)
  1768. {
  1769. if (*name==0)
  1770. name=NULL;
  1771. IXmlScope *top = ensureTopXmlScope(errpos);
  1772. top->getValue(name, ret);
  1773. return ret;
  1774. }
  1775. void HqlLex::setXmlSymbol(const YYSTYPE & errpos, const char *name, const char *value, bool append)
  1776. {
  1777. IXmlScope *top = ensureTopXmlScope(errpos);
  1778. bool ok;
  1779. if (append)
  1780. ok = top->appendValue(name, value);
  1781. else
  1782. ok = top->setValue(name, value);
  1783. if (!ok)
  1784. {
  1785. StringBuffer msg("Symbol has not been declared: ");
  1786. msg.append(name);
  1787. reportError(errpos, ERR_TMPLT_SYMBOLNOTDECLARED, "%s", msg.str());
  1788. }
  1789. }
  1790. void HqlLex::declareXmlSymbol(const YYSTYPE & errpos, const char *name)
  1791. {
  1792. IXmlScope *top = ensureTopXmlScope(errpos);
  1793. if (!top->declareValue(name))
  1794. {
  1795. StringBuffer msg("Symbol has already been declared: ");
  1796. msg.append(name);
  1797. reportError(errpos, ERR_TMPLT_SYMBOLREDECLARE, "%s", msg.str());
  1798. }
  1799. }
  1800. IIterator *HqlLex::getSubScopes(const YYSTYPE & errpos, const char *name, bool doAll)
  1801. {
  1802. IXmlScope *top = ensureTopXmlScope(errpos);
  1803. return top->getScopes(name, doAll);
  1804. }
  1805. void HqlLex::loadXML(const YYSTYPE & errpos, const char *name, const char * child)
  1806. {
  1807. if (xmlScope && child)
  1808. {
  1809. xmlScope->loadXML(name, child);
  1810. return;
  1811. }
  1812. if (false && inmacro)
  1813. {
  1814. inmacro->loadXML(errpos, name);
  1815. return;
  1816. }
  1817. // MORE - give an error if an XML scope is active...
  1818. ::Release(xmlScope);
  1819. try
  1820. {
  1821. xmlScope = ::loadXML(name);
  1822. }
  1823. catch (IException* e)
  1824. {
  1825. e->Release();
  1826. xmlScope = NULL;
  1827. }
  1828. catch (...)
  1829. {
  1830. xmlScope = NULL;
  1831. }
  1832. if (!xmlScope)
  1833. {
  1834. if (name && strlen(name))
  1835. {
  1836. StringBuffer msg;
  1837. msg.appendf("Load XML(\'%s\') failed",name);
  1838. reportError(errpos, ERR_TMPLT_LOADXMLFAILED, "%s", msg.str());
  1839. }
  1840. // recovery: create a default XML scope
  1841. xmlScope = ::loadXML("<xml></xml>");
  1842. }
  1843. }
  1844. IPropertyTree * HqlLex::getClearJavadoc()
  1845. {
  1846. if (javaDocComment.length() == 0)
  1847. return NULL;
  1848. IPropertyTree * tree = createPTree("javadoc");
  1849. extractJavadoc(tree, javaDocComment.str());
  1850. javaDocComment.clear();
  1851. return tree;
  1852. }
  1853. unsigned HqlLex::getTypeSize(unsigned lengthTypeName)
  1854. {
  1855. const char * tok = get_yyText();
  1856. if (strlen(tok)> lengthTypeName)
  1857. return atoi(tok + lengthTypeName);
  1858. return UNKNOWN_LENGTH;
  1859. }
  1860. void HqlLex::enterEmbeddedMode()
  1861. {
  1862. doEnterEmbeddedMode(scanner);
  1863. inCpp = true;
  1864. }
  1865. int HqlLex::yyLex(YYSTYPE & returnToken, bool lookup, const short * activeState)
  1866. {
  1867. loop
  1868. {
  1869. while (inmacro)
  1870. {
  1871. int ret = inmacro->yyLex(returnToken, lookup, activeState);
  1872. if (ret > 0 && ret != HASHBREAK)
  1873. {
  1874. lastToken = ret;
  1875. return ret;
  1876. }
  1877. #if defined(TRACE_MACRO)
  1878. PrintLog("MACRO>> inmacro %p deleted\n", inmacro);
  1879. #endif
  1880. delete inmacro;
  1881. inmacro = NULL;
  1882. if (ret == HASHBREAK)
  1883. {
  1884. if (forLoop)
  1885. {
  1886. forLoop->Release();
  1887. forLoop = NULL;
  1888. }
  1889. else
  1890. {
  1891. lastToken = ret;
  1892. return ret;
  1893. }
  1894. }
  1895. if (forLoop)
  1896. checkNextLoop(returnToken, false,0,0);
  1897. }
  1898. returnToken.clear();
  1899. yyStartPos = yyPosition;
  1900. int ret = doyyFlex(returnToken, scanner, this, lookup, activeState);
  1901. if (ret == 0) ret = EOF;
  1902. if (ret == INTERNAL_READ_NEXT_TOKEN)
  1903. continue;
  1904. if (ret == EOF)
  1905. {
  1906. setTokenPosition(returnToken);
  1907. if (inComment)
  1908. reportError(returnToken, ERR_COMMENT_UNENDED,"Comment is not terminated");
  1909. else if (inCpp)
  1910. reportError(returnToken, ERR_COMMENT_UNENDED,"BEGINC++ or EMBED is not terminated");
  1911. if (hashendDepths.ordinality())
  1912. {
  1913. StringBuffer msg("Unexpected EOF: ");
  1914. msg.append(hashendDepths.ordinality()).append(" more #END needed");
  1915. reportError(returnToken, ERR_TMPLT_HASHENDEXPECTED, "%s", msg.str());
  1916. hashendDepths.kill(); // prevent unnecessary more error messages
  1917. }
  1918. }
  1919. lastToken = ret;
  1920. return ret;
  1921. }
  1922. }