hqltomita.cpp 55 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089
  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 <algorithm>
  14. #include "jliball.hpp"
  15. #include "eclrtl.hpp"
  16. #include "hqlexpr.hpp"
  17. #include "hqlthql.hpp"
  18. #include "hqlcerrors.hpp"
  19. #include "hqlcatom.hpp"
  20. #include "hqlutil.hpp"
  21. #include "hqltomita.ipp"
  22. #include "hqlhtcpp.ipp"
  23. #include "thortparse.ipp"
  24. #include "hqlregex.ipp"
  25. //#define DEFAULT_DFA_COMPLEXITY 0
  26. #define DEFAULT_UNICODE_DFA_COMPLEXITY 0
  27. #define DEFAULT_DFA_COMPLEXITY 2000
  28. //===========================================================================
  29. template <class T>
  30. void cloneLinkedArray(T & target, const T & source)
  31. {
  32. ForEachItemIn(i, source)
  33. target.append(OLINK(source.item(i)));
  34. }
  35. //---------------------------------------------------------------------------
  36. TomFeature::TomFeature(IHqlExpression * expr, TomFeatureKind _kind)
  37. {
  38. def.set(expr);
  39. kind = _kind;
  40. mask = 0;
  41. }
  42. StringBuffer & TomFeature::getDebugText(StringBuffer & out)
  43. {
  44. out.append(" FEATURE ");
  45. getName(out);
  46. switch (kind)
  47. {
  48. case TomMaskFeature:
  49. {
  50. if (values.ordinality())
  51. {
  52. out.append(" := ");
  53. getValue(out);
  54. }
  55. out.append(";");
  56. break;
  57. }
  58. case TomStrFeature:
  59. out.append(" := STRING;");
  60. break;
  61. case TomIntFeature:
  62. out.append(" := INTEGER;");
  63. break;
  64. }
  65. return out.appendf(" // mask(%x)", mask).newline();
  66. }
  67. StringBuffer & TomFeature::getName(StringBuffer & out)
  68. {
  69. if (def && def->queryName())
  70. return out.append(def->queryName());
  71. else
  72. return out.appendf("anon:%p", this);
  73. }
  74. StringBuffer & TomFeature::getValue(StringBuffer & out)
  75. {
  76. ForEachItemIn(idx, values)
  77. {
  78. if (idx) out.append("|");
  79. values.item(idx).getName(out);
  80. }
  81. return out;
  82. }
  83. StringBuffer & TomFeature::getGuardValue(StringBuffer & out)
  84. {
  85. if (def)
  86. return getName(out);
  87. return getValue(out);
  88. }
  89. //---------------------------------------------------------------------------
  90. StringBuffer & TomGuard::getDebugText(StringBuffer & out)
  91. {
  92. if (feature)
  93. feature->getName(out).append("=");
  94. return out;
  95. }
  96. StringBuffer & TomMaskGuard::getDebugText(StringBuffer & out)
  97. {
  98. TomGuard::getDebugText(out);
  99. value->getGuardValue(out);
  100. return out;
  101. }
  102. StringBuffer & TomStrGuard::getDebugText(StringBuffer & out)
  103. {
  104. return TomGuard::getDebugText(out).append('\'').append(value).append('\'');
  105. }
  106. StringBuffer & TomIntGuard::getDebugText(StringBuffer & out)
  107. {
  108. return TomGuard::getDebugText(out).append(value);
  109. }
  110. //---------------------------------------------------------------------------
  111. TomToken::TomToken(IHqlExpression * expr, const TomGuardArray & _guards)
  112. {
  113. pattern.set(expr);
  114. cloneLinkedArray(guards, _guards);
  115. id = NotFound;
  116. }
  117. StringBuffer & TomToken::getDebugText(StringBuffer & out)
  118. {
  119. out.append(" TOKEN<").append(id).append("> ");
  120. getName(out).append(" ");
  121. if (pattern)
  122. {
  123. IHqlExpression * expr = pattern;
  124. if (expr->getOperator() == no_pat_instance)
  125. expr = expr->queryChild(0);
  126. getExprECL(expr->queryBody(), out.append(" := "));
  127. }
  128. return out.append(";").newline();
  129. }
  130. StringBuffer & TomToken::getName(StringBuffer & out)
  131. {
  132. IHqlExpression * expr = pattern;
  133. if (!expr)
  134. return out.append("EOF");
  135. IAtom * name = expr->queryName();
  136. if (expr->getOperator() == no_pat_instance)
  137. name = expr->queryChild(1)->queryName();
  138. if (name)
  139. out.append("tok").append(name);
  140. else if (id != NotFound)
  141. out.appendf("tok%d", id);
  142. else
  143. out.appendf("tok%p", this);
  144. return out;
  145. }
  146. bool TomTokenSet::add(TomToken & other)
  147. {
  148. if (tokens.find(other) == NotFound)
  149. {
  150. tokens.append(other);
  151. return true;
  152. }
  153. other.Release();
  154. return false;
  155. }
  156. bool TomTokenSet::add(TomTokenSet & other)
  157. {
  158. bool changed = false;
  159. ForEachItemIn(idx, other)
  160. {
  161. TomToken & cur = other.item(idx);
  162. if (tokens.find(cur) == NotFound)
  163. {
  164. tokens.append(OLINK(cur));
  165. changed = true;
  166. }
  167. }
  168. return changed;
  169. }
  170. //---------------------------------------------------------------------------
  171. StringBuffer & outputGuards(StringBuffer & out, const TomGuardArray & guards, const char * prefix, const char * suffix)
  172. {
  173. if (guards.ordinality())
  174. {
  175. out.append(prefix);
  176. ForEachItemIn(idx, guards)
  177. {
  178. if (idx) out.append(",");
  179. guards.item(idx).getDebugText(out);
  180. }
  181. out.append(suffix);
  182. }
  183. return out;
  184. }
  185. bool TomStep::calcCanBeNull(bool isRoot, bool & result)
  186. {
  187. return true;
  188. }
  189. bool TomStep::calcFirst(bool isRoot, TomTokenSet & tokens)
  190. {
  191. return true;
  192. }
  193. StringBuffer & TomStep::getDebugText(StringBuffer & out)
  194. {
  195. return out;
  196. }
  197. StringBuffer & TomConditionStep::getDebugText(StringBuffer & out)
  198. {
  199. out.append("(?");
  200. if (rule)
  201. rule->getName(out).append(":");
  202. getExprECL(condition, out);
  203. return out.append("?)");
  204. }
  205. TomGuardStep::TomGuardStep(const TomGuardArray & _guards)
  206. {
  207. cloneLinkedArray(guards, _guards);
  208. }
  209. StringBuffer & TomGuardStep::getDebugText(StringBuffer & out)
  210. {
  211. return outputGuards(out, guards, "[", "]");
  212. }
  213. TomNonTerminalStep::TomNonTerminalStep(TomRule * _rule, const TomGuardArray & _guards)
  214. {
  215. rule = _rule;
  216. cloneLinkedArray(guards, _guards);
  217. }
  218. bool TomNonTerminalStep::calcCanBeNull(bool isRoot, bool & result)
  219. {
  220. return rule->calcCanBeNull(isRoot, result);
  221. }
  222. bool TomNonTerminalStep::calcFirst(bool isRoot, TomTokenSet & tokens)
  223. {
  224. return rule->calcFirst(isRoot, tokens);
  225. }
  226. //-- Non Terminal
  227. bool TomNonTerminalStep::canBeNull()
  228. {
  229. return rule->canBeNull();
  230. }
  231. StringBuffer & TomNonTerminalStep::getDebugText(StringBuffer & out)
  232. {
  233. rule->getName(out);
  234. return outputGuards(out, guards, "{", "}");
  235. }
  236. unsigned TomNonTerminalStep::getId()
  237. {
  238. return rule->getId();
  239. }
  240. TomProduction * TomNonTerminalStep::queryExpandRules()
  241. {
  242. return rule->queryExpand();
  243. }
  244. //-- Penalty
  245. StringBuffer & TomPenaltyStep::getDebugText(StringBuffer & out)
  246. {
  247. return out.append("PENALTY(").append(penalty).append(")");
  248. }
  249. //-- Terminal
  250. bool TomTerminalStep::calcFirst(bool isRoot, TomTokenSet & tokens)
  251. {
  252. tokens.add(*LINK(token));
  253. return true;
  254. }
  255. StringBuffer & TomTerminalStep::getDebugText(StringBuffer & out)
  256. {
  257. return token->getName(out);
  258. }
  259. //-- Use --
  260. TomUseStep::TomUseStep(IHqlExpression * _expr, const TomGuardArray & _guards)
  261. {
  262. expr.set(_expr);
  263. cloneLinkedArray(guards, _guards);
  264. }
  265. TomStep * TomUseStep::expandRecursion(IResolveContext & ctx)
  266. {
  267. TomRule * replacement;
  268. assertex(expr->queryChild(0)->queryValue());
  269. replacement = ctx.queryDefine(expr->queryChild(0));
  270. replacement->addUse();
  271. return new TomNonTerminalStep(replacement, guards);
  272. }
  273. //---------------------------------------------------------------------------
  274. void TomProduction::buildProduction(LRTableBuilder & builder, IHqlExpression * test, GenerateTomitaCtx & ctx)
  275. {
  276. builder.addProduction(id, rule->getId(), rule->queryName(), steps.ordinality(), penalty, transformClonesFirstSymbol());
  277. if (test)
  278. {
  279. switch (test->getOperator())
  280. {
  281. case no_pat_first:
  282. builder.addValidator(id, LRVfirst, 0, 0, NULL);
  283. break;
  284. case no_pat_last:
  285. builder.addValidator(id, LRVlast, 0, 0, NULL);
  286. break;
  287. case no_pat_validate:
  288. {
  289. ValidateKind validatorKind = getValidateKind(ctx.regex.queryValidateExpr(test));
  290. byte op;
  291. switch (ctx.info.type)
  292. {
  293. case type_unicode:
  294. case type_utf8:
  295. op = (validatorKind != ValidateIsString) ? LRVvalidateuni : LRVvalidateasc;
  296. break;
  297. default:
  298. op = (validatorKind != ValidateIsUnicode) ? LRVvalidateasc : LRVvalidateuni;
  299. }
  300. builder.addValidator(id, op, ctx.regex.getValidatorIndex(test), 0, NULL);
  301. break;
  302. }
  303. case no_pat_checklength:
  304. {
  305. unsigned minLength = 0;
  306. unsigned maxLength = PATTERN_UNLIMITED_LENGTH;
  307. getCheckRange(test->queryChild(1), minLength, maxLength, ctx.info.charSize);
  308. builder.addValidator(id, LRVchecklength, minLength, maxLength, NULL);
  309. break;
  310. }
  311. case no_pat_checkin:
  312. {
  313. UNIMPLEMENTED;
  314. /*
  315. AsciiDfa * dfa = NULL;
  316. builder.addValidator(id, LRVcheckin, 0, 0, dfa);
  317. break;
  318. */
  319. }
  320. case no_pat_x_before_y:
  321. case no_pat_before_y:
  322. {
  323. UNIMPLEMENTED;
  324. /*
  325. AsciiDfa * dfa = NULL;
  326. builder.addValidator(id, LRVbefore, 0, 0, dfa);
  327. break;
  328. */
  329. }
  330. case no_pat_x_after_y:
  331. case no_pat_after_y:
  332. {
  333. UNIMPLEMENTED;
  334. /*
  335. unsigned minLength = 0;
  336. unsigned maxLength = 0;
  337. AsciiDfa * dfa = NULL;
  338. builder.addValidator(id, LRVafter, minLength, maxLength, dfa);
  339. break;
  340. */
  341. }
  342. default:
  343. UNIMPLEMENTED;
  344. }
  345. }
  346. }
  347. void TomProduction::buildReduce(LRTableBuilder & builder)
  348. {
  349. rule->buildReduce(builder, this);
  350. }
  351. bool TomProduction::calcCanBeNull(bool isRoot, bool & result)
  352. {
  353. ForEachItemIn(idx, steps)
  354. {
  355. if (!steps.item(idx).calcCanBeNull(isRoot, result))
  356. return false;
  357. if (!result)
  358. return false;
  359. }
  360. result = true;
  361. return true;
  362. }
  363. bool TomProduction::canBeNull()
  364. {
  365. bool result = false;
  366. calcCanBeNull(true, result);
  367. return result;
  368. }
  369. bool TomProduction::calcFirst(bool isRoot, TomTokenSet & result)
  370. {
  371. bool known = true;
  372. ForEachItemIn(idx, steps)
  373. {
  374. TomStep & cur = steps.item(idx);
  375. if (!steps.item(idx).calcFirst(isRoot, result))
  376. known = false;
  377. if (!cur.canBeNull())
  378. break;
  379. }
  380. return known;
  381. }
  382. bool TomProduction::calcFollow()
  383. {
  384. bool changed = false;
  385. unsigned max = steps.ordinality();
  386. ForEachItemIn(idx, steps)
  387. {
  388. TomStep & cur = steps.item(idx);
  389. TomRule * curRule = cur.queryRule();
  390. if (curRule)
  391. {
  392. unsigned nextIdx = idx+1;
  393. for (;nextIdx < max; nextIdx++)
  394. {
  395. TomStep & next = steps.item(nextIdx);
  396. if (curRule->gatherFollow(next))
  397. changed = true;
  398. if (!next.canBeNull())
  399. break;
  400. }
  401. if (nextIdx == max)
  402. if (curRule->gatherFollow(*rule))
  403. changed = true;
  404. }
  405. }
  406. return changed;
  407. }
  408. bool TomProduction::transformClonesFirstSymbol()
  409. {
  410. if (transform)
  411. return false;
  412. if (!rule->queryRecord())
  413. return false;
  414. return queryStep(0) != NULL;
  415. }
  416. void TomProduction::expandRecursion(IResolveContext & ctx)
  417. {
  418. ForEachItemIn(idx, steps)
  419. {
  420. TomStep * replacement = steps.item(idx).expandRecursion(ctx);
  421. if (replacement)
  422. steps.replace(*replacement, idx);
  423. }
  424. }
  425. StringBuffer & TomProduction::getDebugText(StringBuffer & out)
  426. {
  427. out.appendf(" Production<%d>: [", id);
  428. ForEachItemIn(idx, localFeatures)
  429. {
  430. if (idx) out.append(",");
  431. localFeatures.item(idx).getName(out);
  432. }
  433. out.append("]");
  434. if (penalty)
  435. out.append("PENALTY(").append(penalty).append(")");
  436. if (transformClonesFirstSymbol())
  437. out.append(" CloningTransform");
  438. out.append(" := ");
  439. ForEachItemIn(i, steps)
  440. {
  441. if (i) out.append(" ");
  442. steps.item(i).getDebugText(out);
  443. }
  444. return out.newline();
  445. }
  446. bool TomProduction::isSimple(bool singleUse)
  447. {
  448. if (localFeatures.ordinality() || transform)
  449. return false;
  450. if (singleUse)
  451. return true;
  452. return steps.ordinality()<=1;
  453. }
  454. void TomProduction::optimizeRules()
  455. {
  456. ForEachItemInRev(idx, steps)
  457. {
  458. Linked<TomProduction> other = steps.item(idx).queryExpandRules();
  459. if (other)
  460. {
  461. steps.remove(idx);
  462. penalty += other->penalty;
  463. ForEachItemIn(i,other->steps)
  464. steps.add(OLINK(other->steps.item(i)), idx+i);
  465. //MORE: Should inc usage count on rules that are cloned when expanding simple.
  466. //MORE: Should probably do in two passes i) expand if used once. ii) expand simple
  467. }
  468. }
  469. }
  470. //---------------------------------------------------------------------------
  471. TomRule::TomRule(IHqlExpression * expr, IAtom * _name, const TomFeatureArray & _features, bool _implicit, bool _isMatched)
  472. {
  473. def.set(expr);
  474. cloneLinkedArray(features, _features);
  475. implicit = _implicit;
  476. id = 0;
  477. isNull = false;
  478. isNullState = ValueUnknown;
  479. firstState = ValueUnknown;
  480. curExpandState = (unsigned)-1;
  481. numUses = 0;
  482. IHqlExpression * body = expr;
  483. cachedName = _name;
  484. if (body)
  485. {
  486. //skip attribute used to mark an implicit rule
  487. if (body->isAttribute())
  488. body = body->queryChild(0);
  489. if (body->getOperator() == no_pat_featureparam)
  490. body = body->queryChild(0);
  491. if (body->getOperator() == no_define)
  492. defineName.set(body->queryChild(1));
  493. }
  494. isMatched = _isMatched;
  495. }
  496. void TomRule::buildProductions(LRTableBuilder & builder, GenerateTomitaCtx & ctx)
  497. {
  498. ForEachItemIn(idx, productions)
  499. productions.item(idx).buildProduction(builder, test, ctx);
  500. }
  501. void TomRule::buildReduce(LRTableBuilder & builder, TomProduction * production)
  502. {
  503. ForEachItemIn(idx, follow)
  504. builder.addReduce(follow.item(idx).getId(), production->getId());
  505. }
  506. bool TomRule::canBeNull()
  507. {
  508. bool ret = false;
  509. calcCanBeNull(true, ret);
  510. return ret;
  511. }
  512. bool TomRule::calcCanBeNull(bool isRoot, bool & result)
  513. {
  514. if (isNullState == ValueKnown)
  515. {
  516. result = isNull;
  517. return true;
  518. }
  519. if (isNullState == ValueRecursive)
  520. return false;
  521. isNullState = ValueRecursive;
  522. isNull = false;
  523. bool known = true;
  524. ForEachItemIn(idx, productions)
  525. {
  526. if (productions.item(idx).calcCanBeNull(false, isNull))
  527. {
  528. // Short circuit....
  529. if (isNull)
  530. {
  531. result = isNull;
  532. isNullState = ValueKnown;
  533. return true;
  534. }
  535. }
  536. else
  537. known = false;
  538. }
  539. if (isNull)
  540. result = true;
  541. if (!known && !isRoot)
  542. {
  543. isNullState = ValueUnknown;
  544. return false;
  545. }
  546. isNullState = ValueKnown;
  547. return true;
  548. }
  549. bool TomRule::calcFirst(bool isRoot, TomTokenSet & result)
  550. {
  551. if (firstState == ValueKnown)
  552. {
  553. result.add(first);
  554. return true;
  555. }
  556. if (firstState == ValueRecursive)
  557. return false;
  558. firstState = ValueRecursive;
  559. first.kill();
  560. bool known = true;
  561. ForEachItemIn(idx, productions)
  562. {
  563. if (!productions.item(idx).calcFirst(false, first))
  564. known = false;
  565. }
  566. result.add(first);
  567. if (!known && !isRoot)
  568. {
  569. firstState = ValueUnknown;
  570. return false;
  571. }
  572. firstState = ValueKnown;
  573. return true;
  574. }
  575. bool TomRule::calcFollow()
  576. {
  577. bool changed = false;
  578. ForEachItemIn(idx, productions)
  579. if (productions.item(idx).calcFollow())
  580. changed = true;
  581. return changed;
  582. }
  583. void TomRule::expandRecursion(IResolveContext & ctx)
  584. {
  585. ForEachItemIn(idx, productions)
  586. productions.item(idx).expandRecursion(ctx);
  587. }
  588. bool TomRule::gatherFollow(TomRule & next)
  589. {
  590. unsigned num = follow.ordinality();
  591. follow.add(next.follow);
  592. return (num != follow.ordinality());
  593. }
  594. bool TomRule::gatherFollow(TomStep & next)
  595. {
  596. unsigned num = follow.ordinality();
  597. next.calcFirst(true, follow);
  598. return (num != follow.ordinality());
  599. }
  600. StringBuffer & TomRule::getDebugText(StringBuffer & out)
  601. {
  602. out.append(" Rule<").append(id).append("> ");
  603. getName(out);
  604. if (features.ordinality())
  605. {
  606. out.append("{");
  607. ForEachItemIn(idx, features)
  608. {
  609. if (idx) out.append(",");
  610. features.item(idx).getName(out);
  611. }
  612. out.append("}");
  613. }
  614. if (test)
  615. {
  616. out.append(" Test: (");
  617. getExprECL(test, out);
  618. out.append(")");
  619. }
  620. out.newline();
  621. out.appendf(" CanBeNull(%d) First[", canBeNull());
  622. if (firstState == ValueUnknown)
  623. out.append("?");
  624. ForEachItemIn(i1, first)
  625. {
  626. if (i1) out.append(" ");
  627. out.append(first.item(i1).getId());
  628. }
  629. out.append("] Follow[");
  630. ForEachItemIn(i2, follow)
  631. {
  632. if (i2) out.append(" ");
  633. out.append(follow.item(i2).getId());
  634. }
  635. out.append("]").newline();
  636. ForEachItemIn(idx, productions)
  637. productions.item(idx).getDebugText(out);
  638. return out;
  639. }
  640. void TomRule::getFeatures(TomFeatureArray & target)
  641. {
  642. cloneLinkedArray(target, features);
  643. }
  644. StringBuffer & TomRule::getName(StringBuffer & out)
  645. {
  646. if (cachedName)
  647. out.append(cachedName);
  648. else if (id)
  649. out.appendf("rule%d", id);
  650. else
  651. out.appendf("rule%p", this);
  652. return out;
  653. }
  654. bool TomRule::matchesDefine(IHqlExpression * name)
  655. {
  656. return (name == defineName);
  657. }
  658. void TomRule::optimizeRules()
  659. {
  660. ForEachItemIn(idx, productions)
  661. productions.item(idx).optimizeRules();
  662. }
  663. TomProduction * TomRule::queryExpand()
  664. {
  665. if (productions.ordinality() != 1)
  666. return NULL;
  667. if (cachedName && isMatched)
  668. return NULL;
  669. if (test)
  670. return NULL;
  671. TomProduction * first = &productions.item(0);
  672. if (first->isSimple(numUses == 1))
  673. return first;
  674. return NULL;
  675. }
  676. IHqlExpression * TomRule::queryRecord()
  677. {
  678. if (def)
  679. {
  680. if (def->isAttribute() && def->queryName() == tomitaAtom)
  681. return def->queryChild(0)->queryRecord();
  682. return def->queryRecord();
  683. }
  684. return NULL;
  685. }
  686. void TomRule::setProductionIds(HqlExprArray & productionMappings, unsigned & id)
  687. {
  688. ForEachItemIn(idx, productions)
  689. {
  690. TomProduction & cur = productions.item(idx);
  691. cur.setId(id++);
  692. LinkedHqlExpr mapTo = cur.queryTransform();
  693. if (!mapTo && def)
  694. {
  695. IHqlExpression * record = queryRecord();
  696. if (record)
  697. {
  698. if (!cur.queryStep(0))
  699. {
  700. //create a default transform to clear the record.
  701. mapTo.setown(createNullTransform(record));
  702. }
  703. else
  704. {
  705. //Check there is only a single input symbol which has an associated record
  706. TomRule * defaultRule = NULL;
  707. for (unsigned i=0;;i++)
  708. {
  709. TomStep * curStep = cur.queryStep(i);
  710. if (!curStep)
  711. break;
  712. TomRule * curRule = curStep->queryRule();
  713. if (curRule && curRule->queryRecord())
  714. {
  715. if (defaultRule)
  716. throwError(HQLERR_ExpectedTransformManyInputs);
  717. defaultRule = curRule;
  718. }
  719. }
  720. if (!defaultRule || !recordTypesMatch(defaultRule->queryRecord(), record))
  721. throwError(HQLERR_ExpectedTransformManyInputs);
  722. //If so, then don't generate a transform since the input record can be cloned.
  723. mapTo.set(record);
  724. }
  725. }
  726. }
  727. if (mapTo)
  728. productionMappings.append(*createValue(no_mapto, makeVoidType(), createConstant((__int64)cur.getId()), LINK(mapTo)));
  729. }
  730. }
  731. //---------------------------------------------------------------------------
  732. TomitaContext::TomitaContext(IHqlExpression * _expr, IWorkUnit * _wu, const HqlCppOptions & _options)
  733. : NlpParseContext(_expr, _wu, _options), parser(NULL), translatorOptions(_options)
  734. {
  735. numTerminals = 0;
  736. numSymbols = 0;
  737. numProductions = 0;
  738. done = NULL;
  739. gotos = NULL;
  740. maximizeLexer = _options.maximizeLexer;
  741. grammarAmbiguous = false;
  742. }
  743. TomitaContext::~TomitaContext()
  744. {
  745. }
  746. void TomitaContext::addLexerTerminator(IHqlExpression * expr)
  747. {
  748. //NB: expr is know to be valid...
  749. switch (expr->getOperator())
  750. {
  751. case no_list:
  752. {
  753. ForEachChild(idx, expr)
  754. addLexerTerminator(expr->queryChild(idx));
  755. break;
  756. }
  757. case no_constant:
  758. {
  759. ITypeInfo * type = expr->queryType();
  760. const void * value = expr->queryValue()->queryValue();
  761. switch (type->getTypeCode())
  762. {
  763. case type_data:
  764. case type_string:
  765. parser.endTokenChars.append(*(const byte *)value);
  766. break;
  767. case type_utf8:
  768. assertex(rtlUtf8Size(1, value) == 1);
  769. parser.endTokenChars.append(*(const byte *)value);
  770. break;
  771. case type_unicode:
  772. UNIMPLEMENTED;
  773. }
  774. break;
  775. }
  776. }
  777. }
  778. unsigned TomitaContext::addMatchReference(IHqlExpression * expr)
  779. {
  780. if (expr && expr->queryType()->getTypeCode() == type_pattern)
  781. {
  782. StringBuffer s;
  783. s.append(expr->queryName());
  784. if (!s.length())
  785. getExprECL(expr, s);
  786. throwError1(HQLWRN_TomitaMatchPattern, s.str());
  787. }
  788. return NlpParseContext::addMatchReference(expr);
  789. }
  790. void TomitaContext::associateIds()
  791. {
  792. unsigned id=0;
  793. ForEachItemIn(idx1, tokens)
  794. tokens.item(idx1).setId(id++);
  795. numTerminals = id;
  796. ForEachItemIn(idx2, rules)
  797. rules.item(idx2).setId(id++);
  798. numSymbols = id;
  799. }
  800. void TomitaContext::calculateFeatureMasks()
  801. {
  802. }
  803. TomFeature * TomitaContext::createFeature(IHqlExpression * expr)
  804. {
  805. TomFeature * feature = queryFeature(expr);
  806. if (feature)
  807. return feature;
  808. assertex(expr->getOperator() == no_pat_featuredef);
  809. IHqlExpression * def = expr->queryChild(0);
  810. TomFeatureKind kind = TomMaskFeature;
  811. if (def->getOperator() == no_null)
  812. {
  813. switch (def->queryType()->getTypeCode())
  814. {
  815. case type_string:
  816. kind = TomStrFeature;
  817. break;
  818. case type_int:
  819. kind = TomIntFeature;
  820. break;
  821. }
  822. }
  823. feature = new TomFeature(expr, kind);
  824. if (def->getOperator() != no_null)
  825. {
  826. HqlExprArray args;
  827. def->unwindList(args, no_pat_or);
  828. ForEachItemIn(idx, args)
  829. feature->addValue(createFeature(&args.item(idx)));
  830. }
  831. features.append(*feature);
  832. return feature;
  833. }
  834. TomFeature * TomitaContext::createFeatureValue(IHqlExpression * expr)
  835. {
  836. TomFeature * feature = queryFeature(expr);
  837. if (feature)
  838. return feature;
  839. feature = new TomFeature(expr, TomMaskFeature);
  840. HqlExprArray args;
  841. expr->unwindList(args, no_pat_or);
  842. ForEachItemIn(idx, args)
  843. feature->addValue(createFeature(&args.item(idx)));
  844. features.append(*feature);
  845. return feature;
  846. }
  847. void TomitaContext::createFeatures(TomFeatureArray & target, IHqlExpression * expr)
  848. {
  849. if (!expr)
  850. return;
  851. HqlExprArray args;
  852. expr->unwindList(args, no_comma);
  853. ForEachItemIn(idx, args)
  854. target.append(OLINK(*createFeature(&args.item(idx))));
  855. }
  856. TomGuard * TomitaContext::createGuard(IHqlExpression * featureExpr, IHqlExpression * valueExpr)
  857. {
  858. TomFeature * feature = NULL;
  859. if (featureExpr)
  860. feature = createFeature(featureExpr);
  861. switch (valueExpr->queryType()->getTypeCode())
  862. {
  863. case type_feature:
  864. {
  865. TomFeature * value = createFeatureValue(valueExpr);
  866. return new TomMaskGuard(feature, value);
  867. }
  868. case type_string:
  869. {
  870. StringBuffer text;
  871. valueExpr->queryValue()->getStringValue(text);
  872. //MORE: case sensitivity/unicode
  873. IAtom * value = createAtom(text);
  874. return new TomStrGuard(feature, value);
  875. }
  876. case type_int:
  877. {
  878. unsigned value = (unsigned)getIntValue(valueExpr);
  879. return new TomIntGuard(feature, value);
  880. }
  881. default:
  882. UNIMPLEMENTED;
  883. }
  884. }
  885. void TomitaContext::createGuards(TomGuardArray & guards, IHqlExpression * expr)
  886. {
  887. if (!expr)
  888. return;
  889. HqlExprArray args;
  890. expr->unwindList(args, no_comma);
  891. ForEachItemIn(idx, args)
  892. {
  893. IHqlExpression & cur = args.item(idx);
  894. assertex(cur.getOperator() == no_eq);
  895. TomGuard * guard = createGuard(cur.queryChild(0), cur.queryChild(1));
  896. guards.append(*guard);
  897. }
  898. }
  899. void TomitaContext::createImplicitProduction(TomRule * self, TomRule * rule, IHqlExpression * expr, bool expandTokens)
  900. {
  901. switch (expr->getOperator())
  902. {
  903. case no_pat_repeat:
  904. if (!expandTokens)
  905. {
  906. IHqlExpression * action = expr->queryChild(0);
  907. unsigned low = getRepeatMin(expr);
  908. unsigned high = getRepeatMax(expr);
  909. TomProduction * first = new TomProduction(rule);
  910. TomProduction * last = NULL;
  911. if ((low == 0) && (high == 1))
  912. {
  913. last = new TomProduction(rule);
  914. createSteps(self, last, action, expandTokens);
  915. }
  916. else
  917. {
  918. TomRule * actionRule = createImplicitRule(self, action, expandTokens);
  919. TomGuardArray guards;
  920. for (unsigned i = 0; i < low; i++)
  921. first->addStepOwn(new TomNonTerminalStep(actionRule, guards));
  922. if (high != low)
  923. {
  924. if (high == (unsigned)-1)
  925. {
  926. last = new TomProduction(rule);
  927. last->addStepOwn(new TomNonTerminalStep(rule, guards));
  928. last->addStepOwn(new TomNonTerminalStep(actionRule, guards));
  929. }
  930. else
  931. {
  932. if (high - low > 5)
  933. throwError(HQLERR_ArbitaryRepeatUnimplemented);
  934. for (unsigned steps = low+1; steps <= high; steps++)
  935. {
  936. TomProduction * next = new TomProduction(rule);
  937. for (unsigned i = 0; i < steps; i++)
  938. next->addStepOwn(new TomNonTerminalStep(actionRule, guards));
  939. rule->addProductionOwn(next);
  940. }
  941. }
  942. }
  943. }
  944. rule->addProductionOwn(first);
  945. if (last) rule->addProductionOwn(last);
  946. }
  947. else
  948. createProduction(self, rule, expr, expandTokens);
  949. break;
  950. default:
  951. createProduction(self, rule, expr, expandTokens);
  952. break;
  953. }
  954. }
  955. TomRule * TomitaContext::createImplicitRule(TomRule * self, IHqlExpression * expr, bool expandTokens)
  956. {
  957. OwnedHqlExpr wrapped = createAttribute(tomitaAtom, LINK(expr));
  958. TomRule * rule = queryRule(wrapped, NULL);
  959. if (!rule)
  960. {
  961. TomFeatureArray features;
  962. activeRules.tos().getFeatures(features);
  963. rule = new TomRule(wrapped, NULL, features, true, false);
  964. rules.append(*rule);
  965. activeRules.append(*rule);
  966. LinkedHqlExpr body = expr;
  967. switch (expr->getOperator())
  968. {
  969. case no_pat_first:
  970. case no_pat_last:
  971. case no_pat_validate:
  972. case no_pat_checklength:
  973. case no_pat_checkin:
  974. case no_pat_x_before_y:
  975. case no_pat_before_y:
  976. case no_pat_x_after_y:
  977. case no_pat_after_y:
  978. {
  979. rule->setTest(expr);
  980. body.set(body->queryChild(0));
  981. if (!body)
  982. body.setown(createValue(no_null, makePatternType()));
  983. break;
  984. }
  985. }
  986. HqlExprArray args;
  987. body->unwindList(args, no_pat_or);
  988. ForEachItemIn(idx, args)
  989. createImplicitProduction(self, rule, &args.item(idx), expandTokens);
  990. activeRules.pop();
  991. }
  992. return rule;
  993. }
  994. void TomitaContext::createProduction(TomRule * self, TomRule * rule, IHqlExpression * expr, bool expandTokens)
  995. {
  996. TomProduction * production = new TomProduction(rule);
  997. createSteps(self, production, expr, expandTokens);
  998. rule->addProductionOwn(production);
  999. }
  1000. void TomitaContext::createProductions(TomRule * rule, IHqlExpression * expr, bool expandTokens)
  1001. {
  1002. HqlExprArray args;
  1003. expr->unwindList(args, no_pat_or);
  1004. ForEachItemIn(idx, args)
  1005. createProduction(rule, rule, &args.item(idx), expandTokens);
  1006. }
  1007. TomRule * TomitaContext::createRule(IHqlExpression * expr, IAtom * name, bool expandTokens)
  1008. {
  1009. TomRule * rule = queryRule(expr, name);
  1010. if (!rule)
  1011. {
  1012. TomFeatureArray features;
  1013. IHqlExpression * def = expr;
  1014. if (def->getOperator() == no_pat_featureparam)
  1015. {
  1016. createFeatures(features, def->queryChild(1));
  1017. def = def->queryChild(0);
  1018. }
  1019. if (def->getOperator() == no_define)
  1020. def = def->queryChild(0);
  1021. rule = new TomRule(expr, name, features, false, isMatched(expr, name));
  1022. rules.append(*rule);
  1023. activeRules.append(*rule);
  1024. createProductions(rule, def, expandTokens);
  1025. activeRules.pop();
  1026. }
  1027. rule->addUse();
  1028. return rule;
  1029. }
  1030. void TomitaContext::createStepAsImplicitRule(TomRule * self, TomProduction * production, IHqlExpression * expr, bool expandTokens)
  1031. {
  1032. TomRule * rule = createImplicitRule(self, expr, expandTokens);
  1033. TomGuardArray guards;
  1034. production->addStepOwn(new TomNonTerminalStep(rule, guards));
  1035. }
  1036. void TomitaContext::createSteps(TomRule * self, TomProduction * production, IHqlExpression * expr, bool expandTokens)
  1037. {
  1038. switch (expr->getOperator())
  1039. {
  1040. case no_pat_instance:
  1041. {
  1042. IHqlExpression * def = expr->queryChild(0);
  1043. bool canExpand;
  1044. if (maximizeLexer)
  1045. canExpand = canCreateLexerToken(def, false);
  1046. else
  1047. canExpand = isToken(def, expandTokens);
  1048. if (!canExpand)
  1049. {
  1050. if (expr->hasAttribute(_function_Atom))
  1051. createSteps(self, production, def, expandTokens);
  1052. else
  1053. {
  1054. TomGuardArray guards;
  1055. if (def->getOperator() == no_pat_featureactual)
  1056. {
  1057. HqlExprArray actuals;
  1058. def->queryChild(1)->unwindList(actuals, no_comma);
  1059. ForEachItemIn(idx, actuals)
  1060. guards.append(*createGuard(NULL, &actuals.item(idx)));
  1061. def = def->queryChild(0);
  1062. }
  1063. TomRule * rule = createRule(def, expr->queryChild(1)->queryName(), expandTokens);
  1064. production->addStepOwn(new TomNonTerminalStep(rule, guards));
  1065. //MORE: Need to add guards to localFeatures
  1066. }
  1067. return;
  1068. }
  1069. break;
  1070. }
  1071. case no_pat_or:
  1072. //MORE: This changes when we want to extract guard information...
  1073. if (!expandTokens)
  1074. {
  1075. if (expr->numChildren() == 1)
  1076. createSteps(self, production, expr->queryChild(0), expandTokens);
  1077. else
  1078. createStepAsImplicitRule(self, production, expr, expandTokens);
  1079. return;
  1080. }
  1081. break;
  1082. case no_pat_guard:
  1083. {
  1084. TomGuardArray guards;
  1085. createGuards(guards, expr->queryChild(0));
  1086. production->addStepOwn(new TomGuardStep(guards));
  1087. return;
  1088. }
  1089. case no_penalty:
  1090. production->addPenalty((int)getIntValue(expr->queryChild(0)));
  1091. return;
  1092. case no_null:
  1093. //production->addStepOwn(new TomNullStep);
  1094. return;
  1095. case no_pat_case:
  1096. case no_pat_nocase:
  1097. expandTokens = true;
  1098. break;
  1099. case no_pat_first:
  1100. case no_pat_last:
  1101. createStepAsImplicitRule(self, production, expr, expandTokens);
  1102. return;
  1103. }
  1104. if (expandTokens)
  1105. {
  1106. TomToken * token = createToken(expr);
  1107. production->addStepOwn(new TomTerminalStep(token));
  1108. return;
  1109. }
  1110. switch (expr->getOperator())
  1111. {
  1112. case no_pat_imptoken:
  1113. case no_pat_token:
  1114. {
  1115. createSteps(self, production, expr->queryChild(0), true);
  1116. break;
  1117. }
  1118. case no_pat_follow:
  1119. {
  1120. ForEachChild(i, expr)
  1121. createSteps(self, production, expr->queryChild(i), expandTokens);
  1122. break;
  1123. }
  1124. case no_pat_repeat:
  1125. {
  1126. createStepAsImplicitRule(self, production, expr, expandTokens);
  1127. break;
  1128. }
  1129. case no_pat_use:
  1130. {
  1131. //MORE: Should guards be allowed?
  1132. TomGuardArray guards;
  1133. production->addStepOwn(new TomUseStep(expr, guards));
  1134. }
  1135. break;
  1136. case no_self:
  1137. {
  1138. //MORE: Should guards be allowed?
  1139. TomGuardArray guards;
  1140. production->addStepOwn(new TomNonTerminalStep(self, guards));
  1141. break;
  1142. }
  1143. case no_pat_instance:
  1144. createSteps(self, production, expr->queryChild(0), expandTokens);
  1145. break;
  1146. case no_pat_validate:
  1147. case no_pat_checklength:
  1148. case no_pat_checkin:
  1149. case no_pat_x_before_y:
  1150. case no_pat_before_y:
  1151. case no_pat_x_after_y:
  1152. case no_pat_after_y:
  1153. createStepAsImplicitRule(self, production, expr, expandTokens);
  1154. break;
  1155. case no_implicitcast:
  1156. //can sometimes occur when parameters are bound
  1157. createSteps(self, production, expr->queryChild(0), expandTokens);
  1158. break;
  1159. case no_pat_production:
  1160. createSteps(self, production, expr->queryChild(0), expandTokens);
  1161. assertex(!production->transform);
  1162. production->transform.set(expr->queryChild(1));
  1163. break;
  1164. case no_penalty:
  1165. //already handled
  1166. break;
  1167. default:
  1168. UNIMPLEMENTED;
  1169. }
  1170. }
  1171. TomToken * TomitaContext::createToken(IHqlExpression * expr)
  1172. {
  1173. ForEachItemIn(idx, tokens)
  1174. {
  1175. TomToken & cur = tokens.item(idx);
  1176. if (cur.matches(expr))
  1177. return &cur;
  1178. }
  1179. TomGuardArray guards;
  1180. if (expr->getOperator() == no_pat_follow)
  1181. {
  1182. ForEachChild(idx, expr)
  1183. {
  1184. IHqlExpression * cur = expr->queryChild(idx);
  1185. if (cur->getOperator() == no_pat_guard)
  1186. createGuards(guards, cur->queryChild(0));
  1187. }
  1188. }
  1189. TomToken * token = new TomToken(expr, guards);
  1190. tokens.append(*token);
  1191. return token;
  1192. }
  1193. void TomitaContext::compileSearchPattern()
  1194. {
  1195. if (searchType() == type_unicode)
  1196. throwError(HQLERR_TomitaNoUnicode);
  1197. checkValidMatches();
  1198. IHqlExpression * grammar = expr->queryChild(2);
  1199. IHqlExpression * rootSymbol = grammar->queryChild(0);
  1200. assertex(grammar->queryType()->getTypeCode() != type_pattern);
  1201. grammarRule.set(createRule(rootSymbol, grammar->queryChild(1)->queryName(), false));
  1202. //Create an augmented grammar G' with rule S' := S;
  1203. TomFeatureArray noFeatures;
  1204. TomGuardArray noGuards;
  1205. rootRule.setown(new TomRule(NULL, NULL, noFeatures, true, false));
  1206. rootProduction.setown(new TomProduction(rootRule));
  1207. rootProduction->addStepOwn(new TomNonTerminalStep(grammarRule, noGuards));
  1208. rootProduction->setRoot();
  1209. rootRule->addProductionOwn(LINK(rootProduction));
  1210. rules.append(*LINK(rootRule));
  1211. eofToken.setown(new TomToken(NULL, noGuards));
  1212. tokens.append(*LINK(eofToken));
  1213. OwnedHqlExpr nullExpr = createValue(no_null);
  1214. //MORE, create rules for used list...
  1215. expandRecursion();
  1216. optimizeRules();
  1217. associateIds();
  1218. calculateFeatureMasks();
  1219. generateLexer();
  1220. generateParser();
  1221. setParserOptions(parser);
  1222. compileMatched(parser);
  1223. }
  1224. void TomitaContext::generateLexer()
  1225. {
  1226. //nested scope
  1227. try
  1228. {
  1229. RegexContext regex(expr, wu(), translatorOptions, NLPAregexStack);
  1230. regex.beginLexer();
  1231. ForEachItemIn(idx, tokens)
  1232. {
  1233. TomToken & cur = tokens.item(idx);
  1234. if (&cur != eofToken)
  1235. regex.addLexerToken(cur.id, cur.pattern);
  1236. }
  1237. AsciiDfaBuilder builder(parser.tokenDfa);
  1238. regex.generateLexer(&builder);
  1239. }
  1240. catch (IException * e)
  1241. {
  1242. StringBuffer s;
  1243. e->errorMessage(s);
  1244. e->Release();
  1245. throwError1(HQLERR_TomitaPatternTooComplex, s.str());
  1246. }
  1247. IHqlExpression * separator = expr->queryAttribute(separatorAtom);
  1248. if (separator)
  1249. {
  1250. RegexContext regex2(expr, wu(), translatorOptions, NLPAregexStack);
  1251. regex2.beginLexer();
  1252. regex2.addLexerToken(1, separator->queryChild(0));
  1253. AsciiDfaBuilder builder(parser.skipDfa);
  1254. regex2.generateLexer(&builder);
  1255. }
  1256. else
  1257. parser.skipDfa.setEmpty();
  1258. IHqlExpression * terminator = expr->queryAttribute(terminatorAtom);
  1259. if (terminator)
  1260. addLexerTerminator(terminator->queryChild(0));
  1261. parser.eofId = eofToken->getId();
  1262. }
  1263. //-- Parser generation -------------------------------------------------
  1264. //---------------------------------------------------------------------------
  1265. inline int compareLRItem(HqlLRItem * left, HqlLRItem * right)
  1266. {
  1267. if (left->production->seq < right->production->seq)
  1268. return -1;
  1269. if (left->production->seq > right->production->seq)
  1270. return +1;
  1271. if (left->index < right->index)
  1272. return -1;
  1273. if (left->index > right->index)
  1274. return +1;
  1275. return 0;
  1276. }
  1277. int compareLRItem(CInterface * const * left, CInterface * const * right)
  1278. {
  1279. return compareLRItem((HqlLRItem *)*left, (HqlLRItem *)*right);
  1280. }
  1281. void HqlLRItemSet::add(HqlLRItem * value)
  1282. {
  1283. bool isNew;
  1284. CInterface * castValue = value;
  1285. values.bAdd(castValue, compareLRItem, isNew);
  1286. if (!isNew)
  1287. value->Release();
  1288. }
  1289. int HqlLRItemSet::compare(const HqlLRItemSet & other) const
  1290. {
  1291. unsigned numThis = values.ordinality();
  1292. unsigned numOther = other.values.ordinality();
  1293. unsigned numCommon = std::min(numThis, numOther);
  1294. for (unsigned i = 0; i < numCommon; i++)
  1295. {
  1296. HqlLRItem & left = values.item(i);
  1297. HqlLRItem & right = other.values.item(i);
  1298. int c = compareLRItem(&left, &right);
  1299. if (c)
  1300. return c;
  1301. }
  1302. if (numThis > numOther)
  1303. return +1;
  1304. else if (numThis < numOther)
  1305. return -1;
  1306. else
  1307. return 0;
  1308. }
  1309. bool HqlLRItemSet::equals(const HqlLRItemSet & other) const
  1310. {
  1311. unsigned numThis = values.ordinality();
  1312. unsigned numOther = other.values.ordinality();
  1313. if (numThis != numOther)
  1314. return false;
  1315. for (unsigned i = 0; i < numThis; i++)
  1316. {
  1317. if (compareLRItem(&values.item(i), &other.values.item(i)) == 0)
  1318. return false;
  1319. }
  1320. return true;
  1321. }
  1322. StringBuffer & HqlLRGoto::getDebugText(StringBuffer & out)
  1323. {
  1324. return out.append(symbol).append("->").append(state->id);
  1325. }
  1326. void HqlLRState::addItem(TomProduction * production, unsigned idx)
  1327. {
  1328. HqlLRItem * next = new HqlLRItem(production, idx);
  1329. items.add(next);
  1330. }
  1331. void HqlLRState::addGoto(unsigned id, HqlLRState * state)
  1332. {
  1333. gotos.append(*new HqlLRGoto(id, state));
  1334. }
  1335. void HqlLRState::buildNullReductions(LRTableBuilder & builder, TomRule * rule)
  1336. {
  1337. ForEachItemIn(i2, rule->productions)
  1338. {
  1339. TomProduction & curProd = rule->productions.item(i2);
  1340. if (curProd.canBeNull())
  1341. curProd.buildReduce(builder);
  1342. TomStep * first = curProd.queryStep(0);
  1343. if (first)
  1344. {
  1345. TomRule * stepRule = first->queryRule();
  1346. if (stepRule)
  1347. buildNullReductions(builder, stepRule);
  1348. }
  1349. }
  1350. }
  1351. void HqlLRState::buildStateItem(LRTableBuilder & builder, TomProduction * production, unsigned index)
  1352. {
  1353. TomStep * step = production->queryStep(index);
  1354. if (step)
  1355. {
  1356. if (step->isTerminal())
  1357. {
  1358. TomTokenSet tokens;
  1359. step->calcFirst(true, tokens);
  1360. ForEachItemIn(idx, tokens)
  1361. {
  1362. TomToken & cur = tokens.item(idx);
  1363. HqlLRState * gotoState = queryGoto(cur.getId());
  1364. assertex(gotoState);
  1365. builder.addShift(cur.getId(), gotoState->id);
  1366. }
  1367. }
  1368. else
  1369. {
  1370. //Need to be careful. If the a.Xb is in kernal, and X-> is a production then need to include reduce X
  1371. TomRule * rule = step->queryRule();
  1372. if (rule)
  1373. {
  1374. if (!rule->alreadyExpanded(id))
  1375. {
  1376. ForEachItemIn(i2, rule->productions)
  1377. buildStateItem(builder, &rule->productions.item(i2), 0);
  1378. }
  1379. }
  1380. }
  1381. }
  1382. else
  1383. production->buildReduce(builder);
  1384. }
  1385. void HqlLRState::buildState(LRTableBuilder & builder, TomToken * eofToken, unsigned numTerminals)
  1386. {
  1387. builder.beginState(id);
  1388. ForEachItemIn(idx, items)
  1389. {
  1390. HqlLRItem & cur = items.item(idx);
  1391. TomProduction * production = cur.production;
  1392. buildStateItem(builder, production, cur.index);
  1393. if (production->isRootReduction() && (cur.index == 1))
  1394. builder.addAccept(eofToken->getId());
  1395. }
  1396. ForEachItemIn(idx2, gotos)
  1397. {
  1398. HqlLRGoto & cur = gotos.item(idx2);
  1399. if (cur.symbol >= numTerminals)
  1400. builder.addGoto(cur.symbol, cur.state->id);
  1401. }
  1402. builder.endState();
  1403. }
  1404. StringBuffer & HqlLRState::getDebugText(StringBuffer & out)
  1405. {
  1406. out.appendf("\t[%d] I={", id);
  1407. ForEachItemIn(idx, items)
  1408. {
  1409. if (idx) out.append(",");
  1410. items.item(idx).getDebugText(out);
  1411. }
  1412. out.append("} [");
  1413. ForEachItemIn(idx2, gotos)
  1414. {
  1415. if (idx2) out.append(",");
  1416. gotos.item(idx2).getDebugText(out);
  1417. }
  1418. return out.append("]").newline();
  1419. }
  1420. HqlLRState * HqlLRState::queryGoto(token_id id)
  1421. {
  1422. ForEachItemIn(idx, gotos)
  1423. {
  1424. HqlLRGoto & cur = gotos.item(idx);
  1425. if (cur.symbol == id)
  1426. return cur.state;
  1427. }
  1428. return NULL;
  1429. }
  1430. static inline int compareState(HqlLRState * left, HqlLRState * right)
  1431. {
  1432. return left->items.compare(right->items);
  1433. }
  1434. static int compareState(CInterface * const * left, CInterface * const * right)
  1435. {
  1436. return compareState((HqlLRState *)*left, (HqlLRState *)*right);
  1437. }
  1438. void TomitaContext::addGotos(TomProduction * production, unsigned idx)
  1439. {
  1440. //This could be done via virtuals if the context was passed around.
  1441. //but the code is a bit messy.
  1442. unsigned numSteps = production->steps.ordinality();
  1443. if (numSteps == idx)
  1444. return;
  1445. TomStep & step = production->steps.item(idx);
  1446. unsigned id = step.getId();
  1447. if (!gotos[id]) gotos[id] = new HqlLRState;
  1448. gotos[id]->addItem(production, idx+1);
  1449. TomRule * rule = step.queryRule();
  1450. if (rule && !done[id])
  1451. {
  1452. done[id] = true;
  1453. ForEachItemIn(idx, rule->productions)
  1454. {
  1455. TomProduction & cur = rule->productions.item(idx);
  1456. addGotos(&cur, 0);
  1457. }
  1458. }
  1459. }
  1460. HqlLRState * TomitaContext::addState(HqlLRState * state)
  1461. {
  1462. bool isNew = false;
  1463. CInterface * castState = state;
  1464. unsigned matchIndex = orderedStates.bAdd(castState, compareState, isNew);
  1465. if (isNew)
  1466. states.append(*LINK(state));
  1467. else
  1468. state->Release();
  1469. return &orderedStates.item(matchIndex);
  1470. }
  1471. void TomitaContext::calculateStates()
  1472. {
  1473. gotos = new HqlLRState * [numSymbols];
  1474. memset(gotos, 0, sizeof(HqlLRState *) * numSymbols);
  1475. done = new bool[numSymbols];
  1476. try
  1477. {
  1478. HqlLRState * root = new HqlLRState;
  1479. root->addItem(rootProduction, 0);
  1480. rootState.set(addState(root));
  1481. for (unsigned idxState = 0; idxState < states.ordinality(); idxState++)
  1482. {
  1483. memset(done, 0, sizeof(bool) * numSymbols);
  1484. HqlLRState & curState = states.item(idxState);
  1485. ForEachItemIn(idx, curState.items)
  1486. {
  1487. HqlLRItem & curItem = curState.items.item(idx);
  1488. addGotos(curItem.production, curItem.index);
  1489. }
  1490. for (unsigned i= 0; i < numSymbols; i++)
  1491. {
  1492. if (gotos[i])
  1493. {
  1494. HqlLRState * state = addState(gotos[i]);
  1495. curState.addGoto(i, state);
  1496. gotos[i] = NULL;
  1497. }
  1498. }
  1499. }
  1500. }
  1501. catch (...)
  1502. {
  1503. for (unsigned i= 0; i < numSymbols; i++)
  1504. delete gotos[i];
  1505. delete [] gotos;
  1506. delete [] done;
  1507. throw;
  1508. }
  1509. delete [] gotos;
  1510. delete [] done;
  1511. ForEachItemIn(i1, states)
  1512. states.item(i1).id = i1;
  1513. unsigned id = 0;
  1514. ForEachItemIn(i2, rules)
  1515. rules.item(i2).setProductionIds(productions, id);
  1516. numProductions = id;
  1517. }
  1518. void TomitaContext::calculateFollowing()
  1519. {
  1520. //first(x) and canBeNull(x) are calculated on request
  1521. //Need to be careful about recursion: keep repeating until no more items added.
  1522. grammarRule->addFollowOwn(*LINK(eofToken));
  1523. for (;;)
  1524. {
  1525. bool changed = false;
  1526. ForEachItemIn(idx, rules)
  1527. {
  1528. if (rules.item(idx).calcFollow())
  1529. changed = true;
  1530. }
  1531. if (!changed)
  1532. break;
  1533. }
  1534. }
  1535. void TomitaContext::expandRecursion()
  1536. {
  1537. ForEachChild(i1, expr)
  1538. {
  1539. IHqlExpression * cur = expr->queryChild(i1);
  1540. if (cur->getOperator() == no_pat_use)
  1541. createRule(cur->queryChild(0), NULL, false);
  1542. }
  1543. ForEachItemIn(idx, rules)
  1544. rules.item(idx).expandRecursion(*this);
  1545. }
  1546. void TomitaContext::optimizeRules()
  1547. {
  1548. ForEachItemIn(idx, rules)
  1549. {
  1550. TomRule & cur = rules.item(idx);
  1551. if (&cur != rootRule)
  1552. cur.optimizeRules();
  1553. }
  1554. }
  1555. void TomitaContext::generateParser()
  1556. {
  1557. //Following the method described in the dragon book. pp....
  1558. calculateStates();
  1559. calculateFollowing();
  1560. generateTables();
  1561. ForEachItemIn(idx, rules)
  1562. {
  1563. TomRule & cur = rules.item(idx);
  1564. idAllocator.setID(cur.def, cur.queryName(), cur.id);
  1565. }
  1566. }
  1567. void TomitaContext::generateTables()
  1568. {
  1569. GenerateTomitaCtx ctx(*this, info, idAllocator);
  1570. LRTableBuilder builder(parser.table);
  1571. //MORE: Walk and call addGoto etc.
  1572. builder.init(states.ordinality(), numTerminals, numSymbols, numProductions);
  1573. ForEachItemIn(idx, states)
  1574. states.item(idx).buildState(builder, eofToken, numTerminals);
  1575. ForEachItemIn(i1, rules)
  1576. rules.item(i1).buildProductions(builder, ctx);
  1577. builder.finished(rootState->id);
  1578. grammarAmbiguous = builder.isAmbiguous();
  1579. }
  1580. void TomitaContext::getDebugText(StringBuffer & s, unsigned detail)
  1581. {
  1582. NlpParseContext::getDebugText(s, detail);
  1583. s.append("\nFeatures:\n");
  1584. ForEachItemIn(i1, features)
  1585. features.item(i1).getDebugText(s);
  1586. s.append("Tokens:\n");
  1587. ForEachItemIn(i2, tokens)
  1588. tokens.item(i2).getDebugText(s);
  1589. s.append("Rules:\n");
  1590. ForEachItemIn(i3, rules)
  1591. rules.item(i3).getDebugText(s);
  1592. s.append("Lexer:\n");
  1593. s.append("\tEndOfToken: [");
  1594. ForEachItemIn(i, parser.endTokenChars)
  1595. {
  1596. char c = parser.endTokenChars.item(i);
  1597. encodeXML(&c, s, ENCODE_WHITESPACE, 1);
  1598. }
  1599. s.append("]").newline();
  1600. s.append("\tToken DFA");
  1601. parser.tokenDfa.toXML(s, detail);
  1602. s.append("\tSkip DFA");
  1603. parser.skipDfa.toXML(s, detail);
  1604. s.append("\nStates:\n");
  1605. ForEachItemIn(i4, states)
  1606. states.item(i4).getDebugText(s);
  1607. s.append("Parser:\n");
  1608. parser.table.trace(s);
  1609. }
  1610. bool TomitaContext::canCreateLexerToken(IHqlExpression * expr, bool insideOr)
  1611. {
  1612. switch (expr->getOperator())
  1613. {
  1614. case no_null:
  1615. case no_pat_const:
  1616. case no_pat_anychar:
  1617. case no_pat_set:
  1618. return true;
  1619. case no_pat_repeat:
  1620. return isStandardRepeat(expr);
  1621. case no_pat_instance:
  1622. return canCreateLexerToken(expr->queryChild(0), insideOr);
  1623. //depends if used for match...
  1624. return false;
  1625. case no_pat_or:
  1626. {
  1627. ForEachChild(idx, expr)
  1628. {
  1629. if (!canCreateLexerToken(expr->queryChild(idx), true))
  1630. return false;
  1631. }
  1632. return true;
  1633. }
  1634. case no_pat_follow:
  1635. {
  1636. ForEachChild(idx, expr)
  1637. {
  1638. if (!canCreateLexerToken(expr->queryChild(idx), insideOr))
  1639. return false;
  1640. }
  1641. return true;
  1642. }
  1643. default:
  1644. return false;
  1645. }
  1646. }
  1647. bool TomitaContext::isToken(IHqlExpression * expr, bool expandTokens)
  1648. {
  1649. if (!expandTokens)
  1650. {
  1651. /*
  1652. switch (expr->getOperator())
  1653. {
  1654. case no_pat_token:
  1655. case no_pat_imptoken:
  1656. return isToken(expr->queryChild(0), true);
  1657. }
  1658. */
  1659. return false;
  1660. }
  1661. switch (expr->getOperator())
  1662. {
  1663. case no_pat_instance:
  1664. case no_pat_or:
  1665. case no_pat_guard:
  1666. case no_penalty:
  1667. case no_null:
  1668. case no_pat_first:
  1669. case no_pat_last:
  1670. return false;
  1671. default:
  1672. return true;
  1673. }
  1674. }
  1675. TomRule * TomitaContext::queryDefine(IHqlExpression * defineName)
  1676. {
  1677. ForEachItemIn(idx, rules)
  1678. {
  1679. TomRule & cur = rules.item(idx);
  1680. if (cur.matchesDefine(defineName))
  1681. return &cur;
  1682. }
  1683. StringBuffer s;
  1684. defineName->toString(s);
  1685. throwError1(HQLERR_DefineUseStrNotFound, s.str());
  1686. return NULL;
  1687. }
  1688. TomFeature * TomitaContext::queryFeature(IHqlExpression * expr)
  1689. {
  1690. //MORE: May need a hash table!
  1691. ForEachItemIn(idx, features)
  1692. {
  1693. TomFeature & cur = features.item(idx);
  1694. if (cur.matches(expr))
  1695. return &cur;
  1696. }
  1697. return NULL;
  1698. }
  1699. TomRule * TomitaContext::queryRule(IHqlExpression * expr, IAtom * name)
  1700. {
  1701. //MORE: May need a hash table!
  1702. ForEachItemIn(idx, rules)
  1703. {
  1704. TomRule & cur = rules.item(idx);
  1705. if (cur.matches(expr, name))
  1706. return &cur;
  1707. }
  1708. return NULL;
  1709. }
  1710. //---------------------------------------------------------------------------
  1711. NlpParseContext * createTomitaContext(IHqlExpression * expr, IWorkUnit * wu, const HqlCppOptions & options)
  1712. {
  1713. return new TomitaContext(expr, wu, options);
  1714. }
  1715. /*
  1716. ToDo:
  1717. * Features
  1718. o Need to process implicit guards and other conditions.
  1719. o Design how feature actuals are represented and bound.
  1720. o May need guards based on other guards - need to review grammars to see, so can guard a production and also match with others.
  1721. It can be worked around with an intermediate production.
  1722. * Give an error if unicode is used with ,parse
  1723. * Give an error if a token cannot create a DFA
  1724. * Tokens: [+see notes below]
  1725. o Allow before to be included in a token, and use it as the default mechanism for generating tokens.
  1726. o UNKNOWN - pattern matching at different priorities.
  1727. * Validation
  1728. o BEFORE, AFTER [+inverse]
  1729. o pattern IN pattern [+inverse]
  1730. o Non-DFA patterns?
  1731. o Inverse of check length
  1732. * Revisit node packing, and test with the "boy saw the girl" example
  1733. * Reduce number of empty productions e.g., ConnectWord := rule42. Use a flag to indicate top
  1734. * Productions: Allow the order of the symbols to be changed in the graph that is generated.
  1735. * Optimizations:
  1736. o Make position a rolling window so no need to copy
  1737. o best could be processed when packed nodes being built
  1738. * LEFT,RIGHT,NONE to specify precedence of operators + remove s/r conflicts
  1739. Some notes on the algorithms:
  1740. o S->S' in augmented grammar G'
  1741. closure(I) :=
  1742. 1. All items in I.
  1743. 2. If A->a.Bb in closure(I) and B->c is a production then add B->.c
  1744. closure(I)
  1745. {
  1746. J := I
  1747. added = [];
  1748. loop
  1749. for each item A->a.Bb in J
  1750. if !added[B]
  1751. added[B] = true;
  1752. foreach production B->c
  1753. if (B->.c) not in J
  1754. add (B->.c) to J.
  1755. until no mode items added;
  1756. }
  1757. Kernal: S'->.S and all items without dots on lhs.
  1758. Non: items with dots on lhs
  1759. No need to store non-kernal items since adding them can never add any kernals + can always regenerate.
  1760. goto(I, X) := closure of all items [A->aX.b] such that [A->a.Xb] is in I.
  1761. items(G')
  1762. C := closure({S'->.S})
  1763. loop
  1764. for each item I in C
  1765. for each grammar symbol X
  1766. q := goto(I, X);
  1767. if (q is non empty) and q not in C, add q to C.
  1768. until no more items added to C.
  1769. Generating the parsing tables:
  1770. 1. Calculate C := { I... } the items of G'
  1771. 2. If [A->x.ay] is in Ii and goto(Ii,a) = Ij action[i, a] = shift j;
  1772. 3. If [A->x.] is in Ii then action[i, a] := reduce by production for all a in FOLLOW(A) [A may not be S']
  1773. 4. If [S'->S.] in Ii then action[i, $] = accept;
  1774. 5. goto transitions: if gotot(Ii, A) = Ij goto[i, A} := j
  1775. 6. The initial entry is one containing S'->S
  1776. FIRST(x) := set of terminals that begin the strings derived from x
  1777. if (x=>e) then e is also in FIRST(x)
  1778. first(x)
  1779. {
  1780. if (x is a terminal) result = {x}
  1781. if (x->e) is a production, add e to first(x)
  1782. if (x non terminal) and x->y1y2y3, then first(x) = first(y1) + if(first(y1) includes e, first(y2).....)
  1783. - only add e if ALL y1y2y3 include e.
  1784. }
  1785. follow(X) := set of terminals x that can occur to the right of non terminal X in some sentinel form.
  1786. {
  1787. follow(S) = {$}
  1788. repeat
  1789. if a production A->aBb then all in FIRST(b) (except e) is added to follow B.
  1790. if a production A->aB or A->aBb where FIRST(b) includes e. then add everything in follow(A) to follow(B)
  1791. until nothing added to any follow set.
  1792. }
  1793. Tokens:
  1794. * Each token should have an optional set of characters that can or can not follow it.
  1795. * When a token is potentially accepted it should check the set
  1796. i) If specified, and matches then insert a token.
  1797. ii) at end if not-specified then insert a token.
  1798. * repeats aren't specified.
  1799. Reducing the tables:
  1800. i) if rows of the action table are identical, then they can be commoned up
  1801. ii) errors can be converted to reductions without problem.
  1802. iii) can have a list of (symbol, action) pairs instead of an array.
  1803. Ambiguous grammars:
  1804. i) on shift/reduce. Compare precedence of operator being shifted with right most operator in the reduction (or user defined)
  1805. ii) associativity. If the same precedence then if left associative reduce else shift [ should check associativity is the same]
  1806. iii) special rules. Possibly add a commit syntax to imply if this matches don't try and reduce on others?
  1807. */