PageRenderTime 61ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/trunk/src/common/Coding/GScriptCompiler.cpp

#
C++ | 2615 lines | 2056 code | 300 blank | 259 comment | 477 complexity | 5cc7d41d0a30e4494f9d16bd78de8273 MD5 | raw file
Possible License(s): LGPL-2.1, Unlicense

Large files files are truncated, but you can click here to view the full file

  1. /// \file
  2. #include "Lgi.h"
  3. #include "GScripting.h"
  4. #include "GScriptingPriv.h"
  5. #include "GLexCpp.h"
  6. #define GetTok(c) ((c) < Tokens.Length() ? Tokens[c] : 0)
  7. int GFunctionInfo::_Infos = 0;
  8. struct LinkFixup
  9. {
  10. int Tok;
  11. int Offset;
  12. int Args;
  13. GFunctionInfo *Func;
  14. };
  15. struct Node
  16. {
  17. typedef GArray<Node> NodeExp;
  18. struct VariablePart
  19. {
  20. GVariant Name;
  21. NodeExp Array;
  22. };
  23. // Heirarchy
  24. NodeExp Child;
  25. // One of the following are valid:
  26. GOperator Op;
  27. // -or-
  28. bool Constant;
  29. int Tok;
  30. // -or-
  31. GFunc *ContextFunc;
  32. GArray<NodeExp> Args;
  33. // -or-
  34. GFunctionInfo *ScriptFunc;
  35. // -or-
  36. GArray<VariablePart> Variable;
  37. // Used during building
  38. GVarRef Reg;
  39. GVarRef ArrayIdx;
  40. void Init()
  41. {
  42. Op = OpNull;
  43. ContextFunc = 0;
  44. ScriptFunc = 0;
  45. Constant = false;
  46. Tok = -1;
  47. Reg.Empty();
  48. ArrayIdx.Empty();
  49. }
  50. void SetOp(GOperator o, int t)
  51. {
  52. Init();
  53. Op = o;
  54. Tok = t;
  55. }
  56. void SetConst(int t)
  57. {
  58. Init();
  59. Constant = true;
  60. Tok = t;
  61. }
  62. void SetContextFunction(GFunc *m, int tok)
  63. {
  64. Init();
  65. ContextFunc = m;
  66. Tok = tok;
  67. }
  68. void SetScriptFunction(GFunctionInfo *m, int tok)
  69. {
  70. Init();
  71. ScriptFunc = m;
  72. Tok = tok;
  73. }
  74. void SetVar(char16 *Var, int t)
  75. {
  76. Init();
  77. Variable[0].Name = Var;
  78. Tok = t;
  79. }
  80. bool IsVar() { return Variable.Length() > 0; }
  81. bool IsContextFunc() { return ContextFunc != 0; }
  82. bool IsScriptFunc() { return ScriptFunc != 0; }
  83. bool IsConst() { return Constant; }
  84. };
  85. GCompiledCode::GCompiledCode() : Globals(SCOPE_GLOBAL), Debug(0, true, -1, -1)
  86. {
  87. }
  88. GCompiledCode::GCompiledCode(GCompiledCode &copy) : Globals(SCOPE_GLOBAL), Debug(0, true, -1, -1)
  89. {
  90. *this = copy;
  91. }
  92. GCompiledCode::~GCompiledCode()
  93. {
  94. }
  95. GCompiledCode &GCompiledCode::operator =(GCompiledCode &c)
  96. {
  97. Globals = c.Globals;
  98. ByteCode = c.ByteCode;
  99. Types = c.Types;
  100. Debug = c.Debug;
  101. Methods = c.Methods;
  102. return *this;
  103. }
  104. GFunctionInfo *GCompiledCode::GetMethod(const char *Name, bool Create)
  105. {
  106. for (int i=0; i<Methods.Length(); i++)
  107. {
  108. if (!strcmp(Methods[i]->Name.Str(), Name))
  109. return Methods[i];
  110. }
  111. if (Create)
  112. {
  113. GAutoRefPtr<GFunctionInfo> n(new GFunctionInfo) ;
  114. if (n)
  115. {
  116. n->Name = Name;
  117. Methods.Add(n);
  118. return n;
  119. }
  120. }
  121. return 0;
  122. }
  123. GVariant *GCompiledCode::Set(char *Name, GVariant &v)
  124. {
  125. int i = Globals.Var(Name, true);
  126. if (i >= 0)
  127. {
  128. Globals[i] = v;
  129. return &Globals[i];
  130. }
  131. return 0;
  132. }
  133. template <class T>
  134. void UnEscape(T *t)
  135. {
  136. T *i = t, *o = t;
  137. while (*i)
  138. {
  139. if (*i == '\\')
  140. {
  141. i++;
  142. switch (*i)
  143. {
  144. case '\\':
  145. *o++ = '\\'; i++;
  146. break;
  147. case 'n':
  148. *o++ = '\n'; i++;
  149. break;
  150. case 'r':
  151. *o++ = '\r'; i++;
  152. break;
  153. case 't':
  154. *o++ = '\t'; i++;
  155. break;
  156. case 'b':
  157. *o++ = '\b'; i++;
  158. break;
  159. }
  160. }
  161. else *o++ = *i++;
  162. }
  163. *o++ = 0;
  164. }
  165. class TokenRanges
  166. {
  167. struct Range
  168. {
  169. int Start;
  170. GArray<int> Lines;
  171. GVariant File;
  172. };
  173. GArray<Range> r;
  174. public:
  175. void Empty()
  176. {
  177. r.Length(0);
  178. }
  179. int Length()
  180. {
  181. return r.Length();
  182. }
  183. /// Gets the file/line at a given token
  184. char *operator [](int Tok)
  185. {
  186. for (int i=0; i<r.Length(); i++)
  187. {
  188. Range &n = r[i];
  189. if (Tok >= n.Start && Tok < n.Start + n.Lines.Length())
  190. {
  191. static char fl[256];
  192. sprintf(fl, "%s:%i", n.File.Str(), n.Lines[Tok - n.Start]);
  193. return fl;
  194. }
  195. }
  196. return 0;
  197. }
  198. /// Add a file/line reference for the next token
  199. void Add(char *FileName, int Line)
  200. {
  201. const char *Empty = "";
  202. char *d = FileName ? strrchr(FileName, DIR_CHAR) : 0;
  203. if (d) FileName = d + 1;
  204. if (!r.Length())
  205. {
  206. r[0].File = FileName;
  207. r[0].Start = 0;
  208. r[0].Lines.Add(Line);
  209. }
  210. else
  211. {
  212. int Last = r.Length()-1;
  213. char *LastFile = r[Last].File.Str();
  214. if (stricmp(LastFile?LastFile:Empty, FileName?FileName:Empty) != 0)
  215. {
  216. // File changed...
  217. Range &n = r.New();
  218. n.File = FileName;
  219. n.Start = r[Last].Start + r[Last].Lines.Length();
  220. n.Lines.Add(Line);
  221. }
  222. else
  223. {
  224. // Same file...
  225. r[Last].Lines.Add(Line);
  226. }
  227. }
  228. }
  229. };
  230. /// Scripting language compiler implementation
  231. class GCompilerPriv :
  232. public GCompileTools,
  233. public GScriptUtils
  234. {
  235. public:
  236. GScriptContext *Ctx;
  237. GCompiledCode *Code;
  238. GStream *Log;
  239. GArray<char16*> Tokens;
  240. TokenRanges Lines;
  241. char16 *Script;
  242. GHashTable Methods;
  243. int Regs;
  244. GArray<GVariables*> Scopes;
  245. GArray<LinkFixup> Fixups;
  246. GHashTbl<char16*, char16*> Defines;
  247. #ifdef _DEBUG
  248. GArray<GVariant> RegAllocators;
  249. #endif
  250. GCompilerPriv(SystemFunctions *sf)
  251. {
  252. Ctx = 0;
  253. Code = 0;
  254. Log = 0;
  255. Script = 0;
  256. Regs = 0;
  257. GHostFunc *f = sf->GetCommands();
  258. for (int i=0; f[i].Method; i++)
  259. {
  260. f[i].Context = sf;
  261. Methods.Add(f[i].Method, &f[i]);
  262. }
  263. }
  264. ~GCompilerPriv()
  265. {
  266. Empty();
  267. }
  268. void Empty()
  269. {
  270. Ctx = 0;
  271. DeleteObj(Code);
  272. Log = 0;
  273. Tokens.DeleteArrays();
  274. Lines.Empty();
  275. DeleteArray(Script);
  276. Defines.DeleteArrays();
  277. }
  278. bool OnError(int Tok, const char *Msg, ...)
  279. {
  280. if (Log)
  281. {
  282. char Buf[512];
  283. va_list Arg;
  284. va_start(Arg, Msg);
  285. #ifndef WIN32
  286. #define _vsnprintf vsnprintf
  287. #endif
  288. _vsnprintf(Buf, sizeof(Buf)-1, Msg, Arg);
  289. Log->Print("CompileError:%s - %s\n", Lines[Tok], Buf);
  290. va_end(Arg);
  291. }
  292. return false;
  293. }
  294. void DebugInfo(int Tok)
  295. {
  296. char *Line = Lines[Tok];
  297. if (Line)
  298. {
  299. char *c = strrchr(Line, ':');
  300. if (c)
  301. {
  302. Code->Debug.Add(Code->ByteCode.Length(), ::atoi(c+1));
  303. }
  304. }
  305. }
  306. /// Assemble a zero argument instruction
  307. bool Asm0(int Tok, uint8 Op)
  308. {
  309. DebugInfo(Tok);
  310. int Len = Code->ByteCode.Length();
  311. if (Code->ByteCode.Length(Len + 1))
  312. {
  313. GPtr p;
  314. p.u8 = &Code->ByteCode[Len];
  315. *p.u8++ = Op;
  316. }
  317. else return false;
  318. return true;
  319. }
  320. /// Assemble one arg instruction
  321. bool Asm1(int Tok, uint8 Op, GVarRef a)
  322. {
  323. DebugInfo(Tok);
  324. int Len = Code->ByteCode.Length();
  325. if (Code->ByteCode.Length(Len + 5))
  326. {
  327. GPtr p;
  328. p.u8 = &Code->ByteCode[Len];
  329. *p.u8++ = Op;
  330. *p.r++ = a;
  331. }
  332. else return false;
  333. return true;
  334. }
  335. /// Assemble two arg instruction
  336. bool Asm2(int Tok, uint8 Op, GVarRef a, GVarRef b)
  337. {
  338. DebugInfo(Tok);
  339. int Len = Code->ByteCode.Length();
  340. if (Code->ByteCode.Length(Len + 9))
  341. {
  342. GPtr p;
  343. p.u8 = &Code->ByteCode[Len];
  344. *p.u8++ = Op;
  345. *p.r++ = a;
  346. *p.r++ = b;
  347. }
  348. else return false;
  349. return true;
  350. }
  351. /// Assemble three arg instruction
  352. bool Asm3(int Tok, uint8 Op, GVarRef a, GVarRef b, GVarRef c)
  353. {
  354. DebugInfo(Tok);
  355. int Len = Code->ByteCode.Length();
  356. if (Code->ByteCode.Length(Len + 1 + (sizeof(GVarRef) * 3) ))
  357. {
  358. GPtr p;
  359. p.u8 = &Code->ByteCode[Len];
  360. *p.u8++ = Op;
  361. *p.r++ = a;
  362. *p.r++ = b;
  363. *p.r++ = c;
  364. }
  365. else return false;
  366. return true;
  367. }
  368. /// Assemble four arg instruction
  369. bool Asm4(int Tok, uint8 Op, GVarRef a, GVarRef b, GVarRef c, GVarRef d)
  370. {
  371. DebugInfo(Tok);
  372. int Len = Code->ByteCode.Length();
  373. if (Code->ByteCode.Length(Len + 1 + (sizeof(GVarRef) * 4) ))
  374. {
  375. GPtr p;
  376. p.u8 = &Code->ByteCode[Len];
  377. *p.u8++ = Op;
  378. if (!a.Valid()) AllocNull(a);
  379. *p.r++ = a;
  380. if (!b.Valid()) AllocNull(b);
  381. *p.r++ = b;
  382. if (!c.Valid()) AllocNull(c);
  383. *p.r++ = c;
  384. if (!d.Valid()) AllocNull(d);
  385. *p.r++ = d;
  386. }
  387. else return false;
  388. return true;
  389. }
  390. /// Convert the source from one big string into an array of tokens
  391. bool Lex(char *Source, char *FileName)
  392. {
  393. char16 *w = LgiNewUtf8To16(Source);
  394. if (w)
  395. {
  396. int Line = 1;
  397. char16 *s = w, *t, *prev = w;
  398. while (t = LexCpp(s))
  399. {
  400. while (prev < s)
  401. {
  402. if (*prev++ == '\n')
  403. Line++;
  404. }
  405. if (*t == '#')
  406. {
  407. int Len;
  408. if (!StrnicmpW(t + 1, sInclude, Len = StrlenW(sInclude)))
  409. {
  410. char16 *Inc = t + 1 + Len;
  411. char16 *Raw = LexCpp(Inc);
  412. char16 *File = TrimStrW(Raw, (char16*)L"\"\'");
  413. DeleteArray(Raw);
  414. if (File)
  415. {
  416. GVariant v;
  417. char *IncCode = 0;
  418. v.OwnStr(File);
  419. if (IncCode = Ctx->GetIncludeFile(v.Str()))
  420. {
  421. Lex(IncCode, v.Str());
  422. }
  423. else
  424. {
  425. DeleteArray(t);
  426. return OnError(Lines.Length()-1, "Couldn't include '%s'", v.Str());
  427. }
  428. DeleteArray(IncCode);
  429. }
  430. else OnError(Tokens.Length(), "No file for #include.");
  431. }
  432. else if (!StrnicmpW(t + 1, sDefine, Len = StrlenW(sDefine)))
  433. {
  434. char16 *Def = t + 1 + Len;
  435. char16 *Name = LexCpp(Def);
  436. if (isalpha(*Name))
  437. {
  438. Lines.Add(FileName, Line);
  439. Defines.Add(Name, TrimStrW(Def, (char16*)L" \t\r\n"));
  440. }
  441. DeleteArray(Name);
  442. }
  443. DeleteArray(t);
  444. continue;
  445. }
  446. char16 *DefineValue;
  447. if (isalpha(*t) && (DefineValue = Defines.Find(t)))
  448. {
  449. char16 *Def = DefineValue, *f;
  450. while (f = LexCpp(Def))
  451. {
  452. Tokens.Add(f);
  453. Lines.Add(FileName, Line);
  454. }
  455. DeleteArray(t);
  456. }
  457. else
  458. {
  459. Tokens.Add(t);
  460. Lines.Add(FileName, Line);
  461. }
  462. }
  463. if (!Script)
  464. {
  465. Script = w;
  466. }
  467. else
  468. {
  469. DeleteArray(w);
  470. }
  471. return true;
  472. }
  473. return false;
  474. }
  475. /// Create a null var ref
  476. void AllocNull(GVarRef &r)
  477. {
  478. r.Scope = SCOPE_GLOBAL;
  479. if (Code->Globals.NullIndex < 0)
  480. Code->Globals.NullIndex = Code->Globals.Length();
  481. r.Index = Code->Globals.NullIndex;
  482. Code->Globals[r.Index].Type = GV_NULL;
  483. }
  484. /// Allocate a constant double
  485. void AllocConst(GVarRef &r, double d)
  486. {
  487. r.Scope = SCOPE_GLOBAL;
  488. r.Index = Code->Globals.Length();
  489. Code->Globals[r.Index] = d;
  490. }
  491. /// Allocate a constant int
  492. void AllocConst(GVarRef &r, int i)
  493. {
  494. r.Scope = SCOPE_GLOBAL;
  495. if (Code->Globals.Length())
  496. {
  497. // Check for existing int
  498. GVariant *p = &Code->Globals[0];
  499. GVariant *e = p + Code->Globals.Length();
  500. while (p < e)
  501. {
  502. if (p->Type == GV_INT32 &&
  503. p->Value.Int == i)
  504. {
  505. r.Index = p - &Code->Globals[0];
  506. return;
  507. }
  508. p++;
  509. }
  510. }
  511. // Allocate new global
  512. r.Index = Code->Globals.Length();
  513. Code->Globals[r.Index] = i;
  514. }
  515. /// Allocate a constant string
  516. void AllocConst(GVarRef &r, char *s, int len = -1)
  517. {
  518. LgiAssert(s != 0);
  519. if (len < 0)
  520. len = strlen(s);
  521. r.Scope = SCOPE_GLOBAL;
  522. r.Index = Code->Globals.Length();
  523. for (int i=0; i<Code->Globals.Length(); i++)
  524. {
  525. if (Code->Globals[i].Type == GV_STRING)
  526. {
  527. char *c = Code->Globals[i].Str();
  528. if (*s == *c && strcmp(s, c) == 0)
  529. {
  530. r.Index = i;
  531. return;
  532. }
  533. }
  534. }
  535. GVariant &v = Code->Globals[r.Index];
  536. v.Type = GV_STRING;
  537. if (v.Value.String = NewStr(s, len))
  538. {
  539. UnEscape<char>(v.Value.String);
  540. }
  541. }
  542. /// Allocate a constant wide string
  543. void AllocConst(GVarRef &r, char16 *s, int len)
  544. {
  545. LgiAssert(s != 0);
  546. char *utf = LgiNewUtf16To8(s, len * sizeof(char16));
  547. if (!utf)
  548. utf = NewStr("");
  549. r.Scope = SCOPE_GLOBAL;
  550. r.Index = Code->Globals.Length();
  551. for (int i=0; i<Code->Globals.Length(); i++)
  552. {
  553. if (Code->Globals[i].Type == GV_STRING)
  554. {
  555. char *c = Code->Globals[i].Str();
  556. if (*utf == *c && strcmp(utf, c) == 0)
  557. {
  558. r.Index = i;
  559. DeleteArray(utf);
  560. return;
  561. }
  562. }
  563. }
  564. GVariant &v = Code->Globals[r.Index];
  565. v.Type = GV_STRING;
  566. if (v.Value.String = utf)
  567. {
  568. UnEscape<char>(v.Value.String);
  569. }
  570. }
  571. /// Find a variable by name, creating it if needed
  572. GVarRef FindVariable(GVariant &Name, bool Create)
  573. {
  574. GVarRef r = {0, -1};
  575. // Look for existing variable...
  576. int i;
  577. for (i=Scopes.Length()-1; i>=0; i--)
  578. {
  579. r.Index = Scopes[i]->Var(Name.Str(), false);
  580. if (r.Index >= 0)
  581. {
  582. r.Scope = Scopes[i]->Scope;
  583. return r;
  584. }
  585. }
  586. // Create new variable on most recent scope
  587. i = Scopes.Length() - 1;
  588. r.Index = Scopes[i]->Var(Name.Str(), Create);
  589. if (r.Index >= 0)
  590. {
  591. r.Scope = Scopes[i]->Scope;
  592. }
  593. return r;
  594. }
  595. /// Build asm to assign a var ref
  596. bool AssignVarRef(Node &n, GVarRef &Value)
  597. {
  598. /*
  599. Examples and what their assembly should look like:
  600. a = Value
  601. Assign a <- Value
  602. a[b] = Value
  603. R0 = AsmExpression(b);
  604. ArraySet a[R0] <- Value
  605. a[b].c = Value
  606. R0 = AsmExpression(b);
  607. R0 = ArrayGet a[R0]
  608. DomSet(R0, "c", Null, Value)
  609. a[b].c[d]
  610. R0 = AsmExpression(b);
  611. R0 = ArrayGet a[R0];
  612. R1 = AsmExpression(d);
  613. R0 = DomGet(R0, "c", R1);
  614. ArraySet R0[R1] = Value
  615. a.b[c].d = Value
  616. R1 = AsmExpression(c);
  617. R0 = DomGet(a, "b", R1);
  618. DomSet(R1, "d", Null, Value)
  619. // resolve initial array
  620. if (parts > 1 && part[0].array)
  621. {
  622. //
  623. cur = ArrayGet(part[0].var, part[0].array)
  624. }
  625. else
  626. {
  627. cur = part[0]
  628. }
  629. // dom loop over
  630. loop (p = 0 to parts - 2)
  631. {
  632. if (part[p+1].array)
  633. arr = exp(part[p+1].array)
  634. else
  635. arr = null
  636. cur = DomGet(cur, part[p+1].var, arr)
  637. }
  638. // final part
  639. if (part[parts-1].arr)
  640. {
  641. arr = exp(part[parts-1].arr)
  642. ArraySet(cur, arr)
  643. }
  644. else
  645. {
  646. DomSet(cur, part[parts-1].var, null, value)
  647. }
  648. */
  649. if (!n.IsVar())
  650. return false;
  651. // Gets the first part of the variable.
  652. GVarRef Cur = FindVariable(n.Variable[0].Name, true);
  653. if (Cur.Index < 0)
  654. return false;
  655. if (n.Variable.Length() > 1)
  656. {
  657. // Do any initial array dereference
  658. if (n.Variable[0].Array.Length())
  659. {
  660. // Assemble the array index's expression into 'Idx'
  661. GVarRef Idx;
  662. Idx.Empty();
  663. if (!AsmExpression(&Idx, n.Variable[0].Array))
  664. return OnError(n.Tok, "Error creating bytecode for array index.");
  665. GVarRef Dst = Cur;
  666. if (!Dst.IsReg())
  667. {
  668. AllocReg(Dst, _FL);
  669. }
  670. // Assemble array load instruction
  671. Asm3(n.Tok, IArrayGet, Dst, Cur, Idx);
  672. Cur = Dst;
  673. // Cleanup
  674. DeallocReg(Idx);
  675. }
  676. // Do all the DOM "get" instructions
  677. int p;
  678. for (p=0; p<n.Variable.Length() - 2; p++)
  679. {
  680. GVarRef Idx;
  681. Idx.Empty();
  682. // Does the next part have an array deref?
  683. if (n.Variable[p+1].Array.Length())
  684. {
  685. // Evaluate the array indexing expression
  686. if (!AsmExpression(&Idx, n.Variable[p+1].Array))
  687. {
  688. return OnError(n.Tok, "Error creating bytecode for array index.");
  689. }
  690. }
  691. // Alloc constant string for the DOM get
  692. GVarRef DomName;
  693. AllocConst(DomName, n.Variable[p+1].Name.Str());
  694. // Move temp into register?
  695. if (Cur.Scope != SCOPE_REGISTER)
  696. {
  697. GVarRef Dest;
  698. AllocReg(Dest, _FL);
  699. Asm4(n.Tok, IDomGet, Dest, Cur, DomName, Idx);
  700. Cur = Dest;
  701. }
  702. else
  703. {
  704. // Assemble the DOM get instruction
  705. Asm4(n.Tok, IDomGet, Cur, Cur, DomName, Idx);
  706. }
  707. // Cleanup
  708. DeallocReg(Idx);
  709. }
  710. // Do final assignment
  711. GVarRef Idx;
  712. Idx.Empty();
  713. int Last = n.Variable.Length() - 1;
  714. if (n.Variable[Last].Array.Length())
  715. {
  716. // Evaluate the array indexing expression
  717. if (!AsmExpression(&Idx, n.Variable[Last].Array))
  718. {
  719. return OnError(n.Tok, "Error creating bytecode for array index.");
  720. }
  721. }
  722. // Alloc constant string for the DOM get
  723. GVarRef DomName;
  724. AllocConst(DomName, n.Variable[p+1].Name.Str());
  725. // Final instruction to set DOM value
  726. Asm4(n.Tok, IDomSet, Cur, DomName, Idx, Value);
  727. // Cleanup
  728. DeallocReg(Idx);
  729. DeallocReg(Cur);
  730. }
  731. else
  732. {
  733. // Look up the array index if any
  734. if (n.Variable[0].Array.Length())
  735. {
  736. // Assemble the array index's expression into 'Idx'
  737. GVarRef Idx;
  738. Idx.Empty();
  739. if (!AsmExpression(&Idx, n.Variable[0].Array))
  740. return OnError(n.Tok, "Error creating bytecode for array index.");
  741. // Assemble array store instruction
  742. Asm3(n.Tok, IArraySet, Cur, Idx, Value);
  743. // Cleanup
  744. DeallocReg(Idx);
  745. }
  746. else
  747. {
  748. // Non array based assignment
  749. Asm2(n.Tok, IAssign, Cur, Value);
  750. }
  751. }
  752. n.Reg = Value;
  753. return true;
  754. }
  755. /// Convert a token stream to a var ref
  756. bool TokenToVarRef(Node &n)
  757. {
  758. if (!n.Reg.Valid())
  759. {
  760. if (n.IsVar())
  761. {
  762. // Variable
  763. GVarRef v = FindVariable(n.Variable[0].Name, true);
  764. if (v.Index < 0)
  765. return false;
  766. n.Reg = v;
  767. // Does it have an array deref?
  768. if (n.Variable[0].Array.Length())
  769. {
  770. // Evaluate the array indexing expression
  771. if (!AsmExpression(&n.ArrayIdx, n.Variable[0].Array))
  772. {
  773. return OnError(n.Tok, "Error creating bytecode for array index.");
  774. }
  775. // Do we need to create code to load the value from the array?
  776. GVarRef Val;
  777. if (AllocReg(Val, _FL))
  778. {
  779. Asm3(n.Tok, IArrayGet, Val, n.Reg, n.ArrayIdx);
  780. n.Reg = Val;
  781. }
  782. else return OnError(n.Tok, "Error allocating register.");
  783. }
  784. // Load DOM parts...
  785. for (int p=1; p<n.Variable.Length(); p++)
  786. {
  787. GVarRef Name, Arr;
  788. Node::VariablePart &Part = n.Variable[p];
  789. char *nm = Part.Name.Str();
  790. AllocConst(Name, nm, strlen(nm));
  791. if (Part.Array.Length())
  792. {
  793. if (!AsmExpression(&Arr, Part.Array))
  794. {
  795. return OnError(n.Tok, "Can't assemble array expression.");
  796. }
  797. }
  798. else
  799. {
  800. AllocNull(Arr);
  801. }
  802. GVarRef Dst;
  803. if (n.Reg.IsReg())
  804. {
  805. Dst = n.Reg;
  806. }
  807. else
  808. {
  809. AllocReg(Dst, _FL);
  810. }
  811. Asm4(n.Tok, IDomGet, Dst, n.Reg, Name, Arr);
  812. n.Reg = Dst;
  813. }
  814. }
  815. else if (n.IsConst())
  816. {
  817. // Constant
  818. char16 *t = Tokens[n.Tok];
  819. if (*t == '\"' || *t == '\'')
  820. {
  821. // string
  822. int Len = StrlenW(t);
  823. AllocConst(n.Reg, t + 1, Len - 2);
  824. }
  825. else if (StrchrW(t, '.'))
  826. {
  827. // double
  828. AllocConst(n.Reg, atof(t));
  829. }
  830. else if (t[0] == '0' && tolower(t[1]) == 'x')
  831. {
  832. // hex integer
  833. AllocConst(n.Reg, htoi(t + 2));
  834. }
  835. else
  836. {
  837. // decimal integer
  838. AllocConst(n.Reg, atoi(t));
  839. }
  840. }
  841. else if (n.IsContextFunc())
  842. {
  843. // Method call, create byte codes to put func value into n.Reg
  844. if (AllocReg(n.Reg, _FL))
  845. {
  846. GArray<GVarRef> a;
  847. int i;
  848. for (i=0; i<n.Args.Length(); i++)
  849. {
  850. if (!AsmExpression(&a[i], n.Args[i]))
  851. {
  852. return OnError(n.Tok, "Error creating bytecode for context function argument.");
  853. }
  854. }
  855. int Len = Code->ByteCode.Length();
  856. int Size = 1 + sizeof(GFunc*) + sizeof(GVarRef) + 2 + (a.Length() * sizeof(GVarRef));
  857. Code->ByteCode.Length(Len + Size);
  858. GPtr p;
  859. uint8 *Start = &Code->ByteCode[Len];
  860. p.u8 = Start;
  861. *p.u8++ = ICallMethod;
  862. *p.fn++ = n.ContextFunc;
  863. *p.r++ = n.Reg;
  864. *p.u16++ = n.Args.Length();
  865. for (i=0; i<n.Args.Length(); i++)
  866. {
  867. *p.r++ = a[i];
  868. }
  869. LgiAssert(p.u8 == Start + Size);
  870. // Deallocate argument registers
  871. for (i=0; i<a.Length(); i++)
  872. {
  873. DeallocReg(a[i]);
  874. }
  875. }
  876. else return OnError(n.Tok, "Can't allocate register for method return value.");
  877. }
  878. else if (n.IsScriptFunc())
  879. {
  880. // Call to a script function, create byte code to call function
  881. if (AllocReg(n.Reg, _FL))
  882. {
  883. GArray<GVarRef> a;
  884. int i;
  885. for (i=0; i<n.Args.Length(); i++)
  886. {
  887. if (!AsmExpression(&a[i], n.Args[i]))
  888. {
  889. return OnError(n.Tok, "Error creating bytecode for script function argument.");
  890. }
  891. }
  892. int Len = Code->ByteCode.Length();
  893. int Size = 1 + // instruction
  894. sizeof(uint32) + // address of function
  895. sizeof(uint16) + // size of frame
  896. sizeof(GVarRef) + // return value
  897. 2 + // number of args
  898. (a.Length() * sizeof(GVarRef)); // args
  899. Code->ByteCode.Length(Len + Size);
  900. GPtr p;
  901. uint8 *Start = &Code->ByteCode[Len];
  902. p.u8 = Start;
  903. *p.u8++ = ICallScript;
  904. if (n.ScriptFunc->StartAddr)
  905. {
  906. // Compile func address straight into code...
  907. *p.u32++ = n.ScriptFunc->StartAddr;
  908. *p.u16++ = n.ScriptFunc->FrameSize;
  909. }
  910. else
  911. {
  912. // Add link time fixup
  913. LinkFixup &Fix = Fixups.New();
  914. Fix.Tok = n.Tok;
  915. Fix.Args = n.Args.Length();
  916. Fix.Offset = p.u8 - &Code->ByteCode[0];
  917. Fix.Func = n.ScriptFunc;
  918. *p.u32++ = 0;
  919. *p.u16++ = 0;
  920. }
  921. *p.r++ = n.Reg;
  922. *p.u16++ = n.Args.Length();
  923. for (i=0; i<n.Args.Length(); i++)
  924. {
  925. *p.r++ = a[i];
  926. }
  927. LgiAssert(p.u8 == Start + Size);
  928. // Deallocate argument registers
  929. for (i=0; i<a.Length(); i++)
  930. {
  931. DeallocReg(a[i]);
  932. }
  933. }
  934. else return OnError(n.Tok, "Can't allocate register for method return value.");
  935. }
  936. else return false;
  937. }
  938. return true;
  939. }
  940. /// Parse expression into a node tree
  941. bool Expression(int &Cur, GArray<Node> &n, int Depth = 0)
  942. {
  943. if (Cur >= 0 && Cur < Tokens.Length())
  944. {
  945. char16 *t;
  946. bool PrevIsOp = true;
  947. while (t = Tokens[Cur])
  948. {
  949. if (StricmpW(t, sStartRdBracket) == 0)
  950. {
  951. Cur++;
  952. if (!Expression(Cur, n[n.Length()].Child, Depth + 1))
  953. return false;
  954. PrevIsOp = false;
  955. }
  956. else if (StricmpW(t, sEndRdBracket) == 0)
  957. {
  958. if (Depth > 0)
  959. Cur++;
  960. break;
  961. }
  962. else if (StricmpW(t, sComma) == 0 OR
  963. StricmpW(t, sSemiColon) == 0)
  964. {
  965. break;
  966. }
  967. else if (Depth == 0 && StricmpW(t, sEndSqBracket) == 0)
  968. {
  969. break;
  970. }
  971. else
  972. {
  973. GOperator o = IsOp(t, PrevIsOp);
  974. if (o != OpNull)
  975. {
  976. // Operator
  977. PrevIsOp = 1;
  978. n.New().SetOp(o, Cur);
  979. }
  980. else
  981. {
  982. PrevIsOp = 0;
  983. GVariant m;
  984. m = t;
  985. GFunc *f = (GFunc*)Methods.Find(m.Str());
  986. GFunctionInfo *sf = 0;
  987. char16 *Next;
  988. if (f)
  989. {
  990. Node &Call = n.New();
  991. Call.SetContextFunction(f, Cur++);
  992. // Now parse arguments
  993. // Get the start bracket
  994. if (t = GetTok(Cur))
  995. {
  996. if (StricmpW(t, sStartRdBracket) == 0)
  997. Cur++;
  998. else return OnError(Cur, "Function missing '('");
  999. }
  1000. else return OnError(Cur, "No token.");
  1001. // Parse the args as expressions
  1002. while (t = GetTok(Cur))
  1003. {
  1004. if (StricmpW(t, sComma) == 0)
  1005. {
  1006. // Do nothing...
  1007. Cur++;
  1008. }
  1009. else if (StricmpW(t, sEndRdBracket) == 0)
  1010. {
  1011. break;
  1012. }
  1013. else if (!Expression(Cur, Call.Args.New()))
  1014. {
  1015. return OnError(Cur, "Can't parse function argument.");
  1016. }
  1017. }
  1018. }
  1019. else if
  1020. (
  1021. sf = Code->GetMethod
  1022. (
  1023. m.Str(),
  1024. (Next = GetTok(Cur+1)) != 0
  1025. &&
  1026. StricmpW(Next, sStartRdBracket) == 0
  1027. )
  1028. )
  1029. {
  1030. Node &Call = n.New();
  1031. Call.SetScriptFunction(sf, Cur++);
  1032. // Now parse arguments
  1033. // Get the start bracket
  1034. if (t = GetTok(Cur))
  1035. {
  1036. if (StricmpW(t, sStartRdBracket) == 0)
  1037. Cur++;
  1038. else return OnError(Cur, "Function missing '('");
  1039. }
  1040. else return OnError(Cur, "No token.");
  1041. // Parse the args as expressions
  1042. while (t = GetTok(Cur))
  1043. {
  1044. if (StricmpW(t, sComma) == 0)
  1045. {
  1046. // Do nothing...
  1047. Cur++;
  1048. }
  1049. else if (StricmpW(t, sEndRdBracket) == 0)
  1050. {
  1051. break;
  1052. }
  1053. else if (!Expression(Cur, Call.Args[Call.Args.Length()]))
  1054. {
  1055. return OnError(Cur, "Can't parse function argument.");
  1056. }
  1057. }
  1058. }
  1059. else if (isalpha(*t))
  1060. {
  1061. // Variable...
  1062. Node &Var = n.New();
  1063. Var.SetVar(t, Cur);
  1064. while (t = GetTok(Cur+1))
  1065. {
  1066. // Get the last variable part...
  1067. Node::VariablePart &vp = Var.Variable[Var.Variable.Length()-1];
  1068. // Check for array index...
  1069. if (StricmpW(t, sStartSqBracket) == 0)
  1070. {
  1071. // Got array index
  1072. Cur += 2;
  1073. if (!Expression(Cur, vp.Array))
  1074. return OnError(Cur, "Couldn't parse array index expression.");
  1075. if (!(t = GetTok(Cur)) || StricmpW(t, sEndSqBracket) != 0)
  1076. {
  1077. return OnError(Cur, "Expecting ']', didn't get it.");
  1078. }
  1079. t = GetTok(Cur+1);
  1080. }
  1081. // Check for DOM operator...
  1082. if (StricmpW(t, sPeriod) == 0)
  1083. {
  1084. // Got Dom operator
  1085. Cur += 2;
  1086. t = GetTok(Cur);
  1087. if (!t)
  1088. return OnError(Cur, "Unexpected eof.");
  1089. Var.Variable.New().Name = t;
  1090. }
  1091. else break;
  1092. }
  1093. }
  1094. else
  1095. {
  1096. n.New().SetConst(Cur);
  1097. }
  1098. }
  1099. Cur++;
  1100. }
  1101. }
  1102. }
  1103. else
  1104. {
  1105. Log->Print("%s:%i - Unexpected end of file.\n", _FL);
  1106. return false;
  1107. }
  1108. return true;
  1109. }
  1110. /// Allocate a register (must be mirrored with DeallocReg)
  1111. bool AllocReg(GVarRef &r, const char *file, int line)
  1112. {
  1113. for (int i=0; i<MAX_REGISTER; i++)
  1114. {
  1115. int m = 1 << i;
  1116. if ((Regs & m) == 0)
  1117. {
  1118. Regs |= m;
  1119. r.Index = i;
  1120. r.Scope = SCOPE_REGISTER;
  1121. #ifdef _DEBUG
  1122. char s[256];
  1123. sprintf(s, "%s:%i", file, line);
  1124. RegAllocators[i] = s;
  1125. #endif
  1126. return true;
  1127. }
  1128. }
  1129. #ifdef _DEBUG
  1130. if (Log)
  1131. {
  1132. for (int n=0; n<RegAllocators.Length(); n++)
  1133. {
  1134. char *a = RegAllocators[n].Str();
  1135. if (a)
  1136. {
  1137. Log->Print("CompileError:Register[%i] allocated by %s\n", n, a);
  1138. }
  1139. }
  1140. }
  1141. #endif
  1142. return false;
  1143. }
  1144. /// Deallocate a register
  1145. bool DeallocReg(GVarRef &r)
  1146. {
  1147. if (r.Scope == SCOPE_REGISTER && r.Index >= 0)
  1148. {
  1149. int Bit = 1 << r.Index;
  1150. LgiAssert((Bit & Regs) != 0);
  1151. Regs &= ~Bit;
  1152. #ifdef _DEBUG
  1153. RegAllocators[r.Index].Empty();
  1154. #endif
  1155. }
  1156. return true;
  1157. }
  1158. /// Count allocated registers
  1159. int RegAllocCount()
  1160. {
  1161. int c = 0;
  1162. for (int i=0; i<MAX_REGISTER; i++)
  1163. {
  1164. int m = 1 << i;
  1165. if (Regs & m)
  1166. {
  1167. c++;
  1168. }
  1169. }
  1170. return c;
  1171. }
  1172. char *DumpExp(GArray<Node> &n)
  1173. {
  1174. GStringPipe e;
  1175. for (int i=0; i<n.Length(); i++)
  1176. {
  1177. if (n[i].Op)
  1178. {
  1179. e.Print(" op(%i)", n[i].Op);
  1180. }
  1181. else if (n[i].Variable.Length())
  1182. {
  1183. e.Print(" %s", n[i].Variable[0].Name.Str());
  1184. }
  1185. else if (n[i].Constant)
  1186. {
  1187. char16 *t = Tokens[n[i].Tok];
  1188. e.Print(" %S", t);
  1189. }
  1190. else if (n[i].ContextFunc)
  1191. {
  1192. e.Print(" %s(...)", n[i].ContextFunc->Method);
  1193. }
  1194. else if (n[i].ScriptFunc)
  1195. {
  1196. e.Print(" %s(...)", n[i].ScriptFunc->Name.Str());
  1197. }
  1198. else
  1199. {
  1200. e.Print(" #err#");
  1201. }
  1202. }
  1203. return e.NewStr();
  1204. }
  1205. /// Creates byte code to evaluate an expression
  1206. bool AsmExpression
  1207. (
  1208. /// Where the result got stored
  1209. GVarRef *Result,
  1210. /// The nodes to create code for
  1211. GArray<Node> &n,
  1212. /// The depth of recursion
  1213. int Depth = 0
  1214. )
  1215. {
  1216. // Resolve any sub-expressions and store their values
  1217. for (int i = 0; i < n.Length(); i++)
  1218. {
  1219. if (!n[i].IsVar() &&
  1220. n[i].Child.Length())
  1221. {
  1222. AllocReg(n[i].Reg, _FL);
  1223. AsmExpression(&n[i].Reg, n[i].Child, Depth + 1);
  1224. }
  1225. }
  1226. while (n.Length() > 1)
  1227. {
  1228. // Find which operator to handle first
  1229. #ifdef _DEBUG
  1230. int StartLength = n.Length();
  1231. #endif
  1232. int OpIdx = -1;
  1233. int Prec = -1;
  1234. int Ops = 0;
  1235. for (int i=0; i<n.Length(); i++)
  1236. {
  1237. if (n[i].Op)
  1238. {
  1239. Ops++;
  1240. int p = GetPrecedence(n[i].Op);
  1241. if (OpIdx < 0 || p < Prec)
  1242. {
  1243. Prec = p;
  1244. OpIdx = i;
  1245. }
  1246. }
  1247. }
  1248. if (OpIdx < 0)
  1249. {
  1250. GVariant e;
  1251. e.Type = GV_STRING;
  1252. e.Value.String = DumpExp(n);
  1253. return OnError(n[0].Tok, "No operator found in expression '%s'.", e.Str());
  1254. }
  1255. // Evaluate
  1256. GOperator Op = n[OpIdx].Op;
  1257. OperatorType Type = OpType(Op);
  1258. if (Type == OpPrefix ||
  1259. Type == OpPostfix)
  1260. {
  1261. Node &a = n[OpIdx + (Type == OpPrefix ? 1 : -1)];
  1262. if (TokenToVarRef(a))
  1263. {
  1264. GVarRef Reg;
  1265. if (a.Reg.Scope == SCOPE_GLOBAL)
  1266. {
  1267. if (AllocReg(Reg, _FL))
  1268. {
  1269. Asm2(a.Tok, IAssign, Reg, a.Reg);
  1270. a.Reg = Reg;
  1271. }
  1272. else
  1273. {
  1274. LgiAssert(!"Can't alloc register");
  1275. return OnError(a.Tok, "No operator found in expression.");
  1276. }
  1277. }
  1278. Asm1(a.Tok, Op, a.Reg);
  1279. if (Op == OpPostInc || Op == OpPostDec)
  1280. {
  1281. // Write value back to origin
  1282. GVariant &VarName = a.Variable[0].Name;
  1283. GVarRef n = FindVariable(VarName, false);
  1284. if (n.Valid())
  1285. {
  1286. if (a.Child.Length())
  1287. {
  1288. Asm3(a.Tok, IArraySet, n, a.ArrayIdx, a.Reg);
  1289. }
  1290. else if (n != a.Reg)
  1291. {
  1292. Asm2(a.Tok, IAssign, n, a.Reg);
  1293. }
  1294. }
  1295. else
  1296. return OnError(a.Tok, "Symbol '%s' not found.", VarName.Str());
  1297. }
  1298. n.DeleteAt(OpIdx, true);
  1299. }
  1300. else
  1301. {
  1302. LgiAssert(!"Can't turn tokens to refs.");
  1303. return OnError(a.Tok, "Can't turn tokens to refs.");
  1304. }
  1305. }
  1306. else if (Type == OpInfix)
  1307. {
  1308. if (OpIdx - 1 < 0)
  1309. {
  1310. return OnError(n[OpIdx].Tok, "Index %i is not a valid infix location", OpIdx);
  1311. }
  1312. Node &a = n[OpIdx-1];
  1313. Node &b = n[OpIdx+1];
  1314. if (TokenToVarRef(b))
  1315. {
  1316. if ((int)Op == (int)IAssign)
  1317. {
  1318. AssignVarRef(a, b.Reg);
  1319. }
  1320. else if (TokenToVarRef(a))
  1321. {
  1322. GVarRef Reg;
  1323. if (a.Reg.Scope != SCOPE_REGISTER)
  1324. {
  1325. if (AllocReg(Reg, _FL))
  1326. {
  1327. Asm2(a.Tok, IAssign, Reg, a.Reg);
  1328. a.Reg = Reg;
  1329. }
  1330. else return OnError(a.Tok, "Can't alloc register, Regs=0x%x", Regs);
  1331. }
  1332. Asm2(a.Tok, Op, a.Reg, b.Reg);
  1333. if ((int)Op == (int)IPlusEquals ||
  1334. (int)Op == (int)IMinusEquals ||
  1335. (int)Op == (int)IMulEquals ||
  1336. (int)Op == (int)IDivEquals)
  1337. {
  1338. AssignVarRef(a, a.Reg);
  1339. }
  1340. }
  1341. else return OnError(a.Tok, "Can't convert left token to var ref.");
  1342. if (a.Reg != b.Reg)
  1343. DeallocReg(b.Reg);
  1344. n.DeleteAt(OpIdx+1, true);
  1345. n.DeleteAt(OpIdx, true);
  1346. }
  1347. else return OnError(b.Tok, "Can't convert right token to var ref.");
  1348. }
  1349. else
  1350. {
  1351. LgiAssert(!"Not a valid type");
  1352. return OnError(n[0].Tok, "Not a valid type.");
  1353. }
  1354. #ifdef _DEBUG
  1355. if (StartLength == n.Length())
  1356. {
  1357. // No nodes removed... infinite loop!
  1358. LgiAssert(!"No nodes removed.");
  1359. return false;
  1360. }
  1361. #endif
  1362. }
  1363. if (n.Length() == 1)
  1364. {
  1365. if (!n[0].Reg.Valid())
  1366. {
  1367. if (!TokenToVarRef(n[0]))
  1368. {
  1369. return false;
  1370. }
  1371. }
  1372. if (Result)
  1373. {
  1374. *Result = n[0].Reg;
  1375. }
  1376. else
  1377. {
  1378. DeallocReg(n[0].Reg);
  1379. }
  1380. return true;
  1381. }
  1382. return false;
  1383. }
  1384. /// Parses and assembles an expression
  1385. bool DoExpression(int &Cur, GVarRef *Result)
  1386. {
  1387. GArray<Node> n;
  1388. if (Expression(Cur, n))
  1389. {
  1390. bool Status = AsmExpression(Result, n);
  1391. return Status;
  1392. }
  1393. return false;
  1394. }
  1395. /// Parses statements
  1396. bool DoStatements(int &Cur, bool MoreThanOne = true)
  1397. {
  1398. while (Cur < Tokens.Length())
  1399. {
  1400. char16 *t = GetTok(Cur);
  1401. if (!t)
  1402. break;
  1403. if (StricmpW(t, sSemiColon) == 0)
  1404. {
  1405. Cur++;
  1406. if (!MoreThanOne)
  1407. break;
  1408. }
  1409. else if (!StricmpW(t, sReturn))
  1410. {
  1411. Cur++;
  1412. if (!DoReturn(Cur))
  1413. return false;
  1414. }
  1415. else if (!StricmpW(t, sEndCurlyBracket) ||
  1416. !StricmpW(t, sFunction))
  1417. {
  1418. break;
  1419. }
  1420. else if (!StricmpW(t, sIf))
  1421. {
  1422. if (!DoIf(Cur))
  1423. return false;
  1424. }
  1425. else if (!StricmpW(t, sFor))
  1426. {
  1427. if (!DoFor(Cur))
  1428. return false;
  1429. }
  1430. else if (!StricmpW(t, sWhile))
  1431. {
  1432. if (!DoWhile(Cur))
  1433. return false;
  1434. }
  1435. else if (!StricmpW(t, sExtern))
  1436. {
  1437. if (!DoExtern(Cur))
  1438. return false;
  1439. }
  1440. else
  1441. {
  1442. if (!DoExpression(Cur, 0))
  1443. return false;
  1444. }
  1445. }
  1446. return true;
  1447. }
  1448. /// Parses if/else if/else construct
  1449. bool DoIf(int &Cur)
  1450. {
  1451. Cur++;
  1452. char16 *t = GetTok(Cur);
  1453. if (t && !StricmpW(t, sStartRdBracket))
  1454. {
  1455. Cur++;
  1456. // Compile and asm code to evaluate the expression
  1457. GVarRef Result;
  1458. int ExpressionTok = Cur;
  1459. if (DoExpression(Cur, &Result))
  1460. {
  1461. t = GetTok(Cur);
  1462. if (!t || StricmpW(t, sEndRdBracket))
  1463. return OnError(Cur, "if missing ')'.");
  1464. Cur++;
  1465. t = GetTok(Cur);
  1466. if (!t)
  1467. return OnError(Cur, "if missing body statement.");
  1468. // Output the jump instruction
  1469. Asm1(ExpressionTok, IJumpZero, Result);
  1470. DeallocReg(Result);
  1471. int JzOffset = Code->ByteCode.Length();
  1472. Code->ByteCode.Length(JzOffset + sizeof(int32));
  1473. if (!StricmpW(t, sStartCurlyBracket))
  1474. {
  1475. // Statement block
  1476. Cur++;
  1477. while (t = GetTok(Cur))
  1478. {
  1479. if (!StricmpW(t, sSemiColon))
  1480. {
  1481. Cur++;
  1482. }
  1483. else if (!StricmpW(t, sEndCurlyBracket))
  1484. {
  1485. Cur++;
  1486. break;
  1487. }
  1488. else if (!DoStatements(Cur))
  1489. {
  1490. return false;
  1491. }
  1492. }
  1493. }
  1494. else
  1495. {
  1496. // Single statement
  1497. if (!DoStatements(Cur, false))
  1498. return false;
  1499. }
  1500. // Check for else...
  1501. if ((t = GetTok(Cur)) && StricmpW(t, sElse) == 0)
  1502. {
  1503. // Add a jump for the "true" part of the expression to
  1504. // jump over the "else" part.
  1505. Asm0(Cur, IJump);
  1506. int JOffset = Code->ByteCode.Length();
  1507. if (Code->ByteCode.Length(JOffset + 4))
  1508. {
  1509. // Initialize the ptr to zero
  1510. int32 *Ptr = (int32*)&Code->ByteCode[JOffset];
  1511. *Ptr = 0;
  1512. // Resolve jz to here...
  1513. if (JzOffset)
  1514. {
  1515. // Adjust the "if" jump point
  1516. int32 *Ptr = (int32*)&Code->ByteCode[JzOffset];
  1517. *Ptr = Code->ByteCode.Length() - JzOffset - sizeof(int32);
  1518. JzOffset = 0;
  1519. }
  1520. // Compile the else block
  1521. Cur++;
  1522. if ((t = GetTok(Cur)) && StricmpW(t, sStartCurlyBracket) == 0)
  1523. {
  1524. // 'Else' Statement block
  1525. Cur++;
  1526. while (t = GetTok(Cur))
  1527. {
  1528. if (!StricmpW(t, sSemiColon))
  1529. {
  1530. Cur++;
  1531. }
  1532. else if (!StricmpW(t, sEndCurlyBracket))
  1533. {
  1534. Cur++;
  1535. break;
  1536. }
  1537. else if (!DoStatements(Cur))
  1538. {
  1539. return false;
  1540. }
  1541. }
  1542. }
  1543. else
  1544. {
  1545. // Single statement
  1546. if (!DoStatements(Cur, false))
  1547. return false;
  1548. }
  1549. // Resolve the "JOffset" jump that takes execution of
  1550. // the 'true' part over the 'else' part
  1551. Ptr = (int32*)&Code->ByteCode[JOffset];
  1552. *Ptr = Code->ByteCode.Length() - JOffset - sizeof(int32);
  1553. if (*Ptr == 0)
  1554. {
  1555. // Empty statement... so delete the Jump instruction
  1556. Code->ByteCode.Length(JOffset - 1);
  1557. }
  1558. }
  1559. else OnError(Cur, "Mem alloc");
  1560. }
  1561. if (JzOffset)
  1562. {
  1563. // Adjust the jump point
  1564. int32 *Ptr = (int32*)&Code->ByteCode[JzOffset];
  1565. int CurLen = Code->ByteCode.Length();
  1566. *Ptr = CurLen - JzOffset - sizeof(int32);
  1567. LgiAssert(*Ptr);
  1568. }
  1569. return true;
  1570. }
  1571. }
  1572. else return OnError(Cur, "if missing '('");
  1573. return false;
  1574. }
  1575. GArray<uint8> &GetByteCode()
  1576. {
  1577. return Code->ByteCode;
  1578. }
  1579. class GJumpZero
  1580. {
  1581. GCompilerPriv *Comp;
  1582. int JzOffset;
  1583. public:
  1584. GJumpZero(GCompilerPriv *d, int &Cur, GVarRef &r)
  1585. {
  1586. // Create jump instruction to jump over the body if the expression evaluates to false
  1587. Comp = d;
  1588. Comp->Asm1(Cur, IJumpZero, r);
  1589. Comp->DeallocReg(r);
  1590. JzOffset = Comp->GetByteCode().Length();
  1591. Comp->GetByteCode().Length(JzOffset + sizeof(int32));
  1592. }
  1593. ~GJumpZero()
  1594. {
  1595. // Resolve jump
  1596. int32 *Ptr = (int32*) &Comp->GetByteCode()[JzOffset];
  1597. *Ptr = Comp->GetByteCode().Length() - (JzOffset + sizeof(int32));
  1598. }
  1599. };
  1600. /// Parses while construct
  1601. bool DoWhile(int &Cur)
  1602. {
  1603. Cur++;
  1604. char16 *t = GetTok(Cur);
  1605. if (!t || StricmpW(t, sStartRdBracket))
  1606. return OnError(Cur, "Expecting '(' after 'while'");
  1607. Cur++;
  1608. // Store start of condition code
  1609. int ConditionStart = Code->ByteCode.Length();
  1610. // Compile condition evalulation
  1611. GVarRef r;
  1612. if (!DoExpression(Cur, &r))
  1613. return false;
  1614. // Create jump instruction to jump over the body if the expression evaluates to false
  1615. {
  1616. GJumpZero Jump(this, Cur, r);
  1617. if (!(t = GetTok(Cur)) || StricmpW(t, sEndRdBracket))
  1618. return OnError(Cur, "Expecting ')'");
  1619. Cur++;
  1620. // Compile the body of the loop
  1621. if (!(t = GetTok(Cur)))
  1622. return OnError(Cur, "Unexpected eof.");
  1623. Cur++;
  1624. if (StricmpW(t, sStartCurlyBracket) == 0)
  1625. {
  1626. // Block
  1627. while (t = GetTok(Cur))
  1628. {
  1629. if (!StricmpW(t, sSemiColon))
  1630. {
  1631. Cur++;
  1632. }
  1633. else if (!StricmpW(t, sEndCurlyBracket))
  1634. {
  1635. Cur++;
  1636. break;
  1637. }
  1638. else if (!DoStatements(Cur))
  1639. {
  1640. return false;
  1641. }
  1642. }
  1643. }
  1644. else
  1645. {
  1646. // Single statement
  1647. DoStatements(Cur, false);
  1648. }
  1649. // Jump to condition evaluation at 'ConditionStart'
  1650. Asm0(Cur, IJump);
  1651. int JOffset = Code->ByteCode.Length();
  1652. Code->ByteCode.Length(JOffset + sizeof(int32));
  1653. int32 *Ptr = (int32*) &Code->ByteCode[JOffset];
  1654. *Ptr = ConditionStart - Code->ByteCode.Length();
  1655. }
  1656. return true;
  1657. }
  1658. /// Parses for construct
  1659. bool DoFor(int &Cur)
  1660. {
  1661. /*
  1662. For loop asm structure:
  1663. +---------------------------+
  1664. | Pre-condition expression |
  1665. +---------------------------+
  1666. | Eval loop contdition exp. |<--+
  1667. | | |
  1668. | JUMP ZERO (jumpz) |---+-+
  1669. +---------------------------+ | |
  1670. | Body of loop... | | |
  1671. | | | |
  1672. | | | |
  1673. | | | |
  1674. | | | |
  1675. | | | |
  1676. +---------------------------+ | |
  1677. | Post-cond. expression | | |
  1678. | | | |
  1679. | JUMP |---+ |
  1680. +---------------------------+ |
  1681. | Following code... |<----+
  1682. . .
  1683. */
  1684. Cur++;
  1685. char16 *t = GetTok(Cur);
  1686. if (!t || StricmpW(t, sStartRdBracket))
  1687. return OnError(Cur, "Expecting '(' after 'for'");
  1688. Cur++;
  1689. // Compile initial statement
  1690. GVarRef r;
  1691. t = GetTok(Cur);
  1692. if (!t)
  1693. return false;
  1694. if (StricmpW(t, sSemiColon) && !DoExpression(Cur, 0))
  1695. return false;
  1696. t = GetTok(Cur);
  1697. // Look for ';'
  1698. if (!t || StricmpW(t, sSemiColon))
  1699. return OnError(Cur, "Expecting ';'");
  1700. Cur++;
  1701. // Store start of condition code
  1702. int ConditionStart = Code->ByteCode.Length();
  1703. // Compile condition evalulation
  1704. if (!DoExpression(Cur, &r))
  1705. return false;
  1706. {
  1707. GJumpZero Jmp(this, Cur, r);
  1708. t = GetTok(Cur);
  1709. // Look for ';'
  1710. if (!t || StricmpW(t, sSemiColon))
  1711. return OnError(Cur, "Expecting ';'");
  1712. Cur++;
  1713. // Compile the post expression code
  1714. int PostCodeStart = Code->ByteCode.Length();
  1715. t = GetTok(Cur);
  1716. if (StricmpW(t, sEndRdBracket) && !DoExpression(Cur, 0))
  1717. return false;
  1718. // Store post expression code in temp variable
  1719. GArray<uint8> PostCode;
  1720. int PostCodeLen = Code->ByteCode.Length() - PostCodeStart;
  1721. if (PostCodeLen)
  1722. {
  1723. PostCode.Length(PostCodeLen);
  1724. memcpy(&PostCode[0], &Code->ByteCode[PostCodeStart], PostCodeLen);
  1725. // Delete the post expression off the byte code, we are putting it after the block code
  1726. Code->ByteCode.Length(PostCodeStart);
  1727. }
  1728. // Look for ')'
  1729. t = GetTok(Cur);
  1730. if (!t || StricmpW(t, sEndRdBracket))
  1731. return OnError(Cur, "Expecting ')'");
  1732. Cur++;
  1733. // Compile body of loop
  1734. if ((t = GetTok(Cur)) && StricmpW(t, sStartCurlyBracket) == 0)
  1735. {
  1736. Cur++;
  1737. while (t = GetTok(Cur))
  1738. {
  1739. if (!StricmpW(t, sSemiColon))
  1740. {
  1741. Cur++;
  1742. }
  1743. else if (!StricmpW(t, sEndCurlyBracket))
  1744. {
  1745. Cur++;
  1746. break;
  1747. }
  1748. else if (!DoStatements(Cur))
  1749. {
  1750. return false;
  1751. }
  1752. }
  1753. }
  1754. // Add post expression code
  1755. if (PostCodeLen)
  1756. {
  1757. int Len = Code->ByteCode.Length();
  1758. Code->ByteCode.Length(Len + PostCodeLen);
  1759. memcpy(&Code->ByteCode[Len], &PostCode[0], PostCodeLen);
  1760. }
  1761. // Jump to condition evaluation at 'ConditionStart'
  1762. Asm0(Cur, IJump);
  1763. int JOffset = Code->ByteCode.Length();
  1764. Code->ByteCode.Length(JOffset + sizeof(int32));
  1765. int32 *Ptr = (int32*) &Code->ByteCode[JOffset];
  1766. *Ptr = ConditionStart - Code->ByteCode.Length();
  1767. }
  1768. return true;
  1769. }
  1770. /// Compiles return construct
  1771. bool DoReturn(int &Cur)
  1772. {
  1773. GVarRef ReturnValue;
  1774. char16 *t;
  1775. GArray<Node> Exp;
  1776. if (!Expression(Cur, Exp))
  1777. {
  1778. return OnError(Cur, "Failed to compile return expression.");
  1779. }
  1780. else if (!AsmExpression(&ReturnValue, Exp))
  1781. {
  1782. return OnError(Cur, "Failed to assemble return expression.");
  1783. }
  1784. if (!(t = GetTok(Cur)) ||
  1785. StricmpW(t, sSemiColon))
  1786. {
  1787. return OnError(Cur, "Expecting ';' after return expression.");
  1788. }
  1789. Cur++;
  1790. Asm1(Cur, IRet, ReturnValue);
  1791. return true;
  1792. }
  1793. // Compile a method definition
  1794. bool DoFunction(int &Cur)
  1795. {
  1796. bool Status = false;
  1797. bool LastInstIsReturn = false;
  1798. GVariant FunctionName;
  1799. char16 *Name = GetTok(Cur);
  1800. if (Name)
  1801. {
  1802. Cur++;
  1803. char16 *t = GetTok(Cur);
  1804. if (!t || StricmpW(t, sStartRdBracket))
  1805. return OnError(Cur, "Expecting '(' in function.");
  1806. FunctionName = Name;
  1807. GFunctionInfo *f = Code->GetMethod(FunctionName.Str(), true);
  1808. if (!f)
  1809. return OnError(Cur, "Can't define method '%s'.", FunctionName.Str());
  1810. f->Name = t;
  1811. f->StartAddr = Code->ByteCode.Length();
  1812. // Parse parameters
  1813. Cur++;
  1814. while (t = GetTok(Cur))
  1815. {
  1816. if (isalpha(*t))
  1817. {
  1818. f->Params.New() = t;
  1819. Cur++;
  1820. if (!(t = GetTok(Cur)))
  1821. goto UnexpectedFuncEof;
  1822. }
  1823. if (!StricmpW(t, sComma))
  1824. ;
  1825. else if (!StricmpW(t, sEndRdBracket))
  1826. {
  1827. Cur++;
  1828. break;
  1829. }
  1830. else
  1831. goto UnexpectedFuncEof;
  1832. Cur++;
  1833. }
  1834. // Parse start of body
  1835. if (!(t = GetTok(Cur)))
  1836. goto UnexpectedFuncEof;
  1837. if (StricmpW(t, sStartCurlyBracket))
  1838. return OnError(Cur, "Expecting '{'.");
  1839. // Setup new scope
  1840. GVariables LocalScope(SCOPE_LOCAL);
  1841. Scopes.Add(&LocalScope);
  1842. for (int i=0; i<f->Params.Length(); i++)
  1843. {
  1844. LocalScope.Var(f->Params[i].Str(), true);
  1845. }
  1846. // Parse contents of function body
  1847. Cur++;
  1848. while (t = GetTok(Cur))
  1849. {
  1850. // Return statement?
  1851. if (LastInstIsReturn = (!StricmpW(t, sReturn)))
  1852. {
  1853. Cur++;
  1854. if (!DoReturn(Cur))
  1855. return false;
  1856. if (!(t = GetTok(Cur)))
  1857. return OnError(Cur, "Unexpected EOF.");
  1858. }
  1859. // End of the function?
  1860. if (!StricmpW(t, sEndCurlyBracket))
  1861. {
  1862. f->Name = Name;
  1863. f->FrameSize = LocalScope.Length();
  1864. Status = true;
  1865. Cur++;
  1866. // LgiTrace("Added method %s @ %i, stack=%i, args=%i\n", f->Name.Str(), f->StartAddr, f->FrameSize, f->Params.Length());
  1867. break;
  1868. }
  1869. // Parse statment in the body
  1870. if (DoStatements(Cur))
  1871. LastInstIsReturn = false;
  1872. else
  1873. return OnError(Cur, "Can't compile function body.");
  1874. }
  1875. // Remove local scope from scopes
  1876. Scopes.Length(Scopes.Length()-1);
  1877. }
  1878. if (!LastInstIsReturn)
  1879. {
  1880. GVarRef RetVal;
  1881. AllocNull(RetVal);
  1882. Asm1(Cur, IRet, RetVal);
  1883. }
  1884. return Status;
  1885. UnexpectedFuncEof:
  1886. return OnError(Cur, "Unexpected EOF in function.");
  1887. }
  1888. /// Compiles struct construct
  1889. bool DoStruct(int &Cur)
  1890. {
  1891. bool Status = false;
  1892. GHashTbl<const char*, GVariantType> Types;
  1893. Types.Add("int32", GV_INT32);
  1894. Types.Add("int", GV_INT32);
  1895. Types.Add("int64", GV_INT64);
  1896. Types.Add("bool", GV_BOOL);
  1897. Types.Add("boolean", GV_BOOL);
  1898. Types.Add("double", GV_DOUBLE);
  1899. Types.Add("float", GV_DOUBLE);
  1900. Types.Add("char", GV_STRING);
  1901. Types.Add("GDom", GV_DOM);
  1902. Types.Add("void", GV_VOID_PTR);
  1903. Types.Add("GDateTime", GV_DATETIME);
  1904. Types.Add("GHashTable", GV_HASHTABLE);
  1905. Types.Add("GOperator", GV_OPERATOR);
  1906. Types.Add("GView", GV_GVIEW);
  1907. Types.Add("GMouse", GV_GMOUSE);
  1908. Types.Add("GKey", GV_GKEY);
  1909. // Types.Add("binary", GV_BINARY);
  1910. // Types.Add("List", GV_LIST);
  1911. // Types.Add("GDom&", GV_DOMREF);
  1912. // Parse struct name and setup a type
  1913. char16 *t;
  1914. GTypeDef *Def = Code->Types.Find(t = GetTok(Cur));
  1915. if (!Def)
  1916. Code->Types.Add(t, Def = new GTypeDef(t));
  1917. Cur++;
  1918. t = GetTok(Cur);
  1919. if (!t || StricmpW(t, sStartCurlyBracket))
  1920. return OnError(Cur, "Expecting '{'");
  1921. Cur++;
  1922. // Parse members
  1923. while (t = GetTok(Cur))
  1924. {
  1925. // End of type def?
  1926. if (!StricmpW(t, sEndCurlyBracket))
  1927. {
  1928. Cur++;
  1929. t = GetTok(Cur);
  1930. if (!t || StricmpW(t, sSemiColon))
  1931. return OnError(Cur, "Expecting ';' after '}'");
  1932. Status = true;
  1933. break;
  1934. }
  1935. // Parse member field
  1936. GVariant TypeName = t;
  1937. GTypeDef *NestedType = 0;
  1938. GVariantType Type = Types.Find(TypeName.Str());
  1939. if (!Type)
  1940. {
  1941. // Check other custom types
  1942. NestedType = Code->GetType(t);
  1943. if (!NestedType)
  1944. return OnError(Cur, "Unknown type '%S' in struct definition.", t);
  1945. // Ok, nested type.
  1946. Type = GV_CUSTOM;
  1947. }
  1948. Cur++;
  1949. if (!(t = GetTok(Cur)))
  1950. goto EofError;
  1951. bool Pointer = false;
  1952. if (t[0] == '*' && t[1] == 0)
  1953. {
  1954. Pointer = true;
  1955. Cur++;
  1956. if (!(t = GetTok(Cur)))
  1957. goto EofError;
  1958. }
  1959. GVariant Name = t;
  1960. Cur++;
  1961. if (!(t = GetTok(Cur)))
  1962. goto EofError;
  1963. int Array = 0;
  1964. if (!StricmpW(t, sStartSqBracket))
  1965. {
  1966. // Array
  1967. Cur++;
  1968. if (!(t = GetTok(Cur)))
  1969. goto EofError;
  1970. Array = atoi(t);
  1971. Cur++;
  1972. if (!(t = GetTok(Cur)))
  1973. goto EofError;
  1974. if (StricmpW(t, sEndSqBracket))
  1975. return OnError(Cur, "Expecting ']' in array definition.");
  1976. Cur++;
  1977. }
  1978. GTypeDef::GMember *Mem = Def->Members.Find(Name.Str());
  1979. if (Mem)
  1980. return OnError(Cur, "Member '%s' can't be defined twice.", Name.Str());
  1981. if (!(Mem = new GTypeDef::GMember))
  1982. return OnError(Cur, "Alloc.");
  1983. Mem->Offset = Def->Size;
  1984. Mem->Array = Array;
  1985. Mem->Type = Type;
  1986. Mem->Nest = NestedType;
  1987. if (Mem->Pointer = Pointer)
  1988. {
  1989. Mem->Size = sizeof(void*);
  1990. }
  1991. else
  1992. {
  1993. switch (Mem->Type)
  1994. {
  1995. case GV_INT32:
  1996. Mem->Size = sizeof(int32);
  1997. break;
  1998. case GV_INT64:
  1999. Mem->Size = sizeof(int64);
  2000. break;
  2001. case GV_BOOL:
  2002. Mem->Size = sizeof(bool);
  2003. break;
  2004. case GV_DOUBLE:
  2005. Mem->Size = sizeof(double);
  2006. break;
  2007. case GV_STRING:
  2008. Mem->Size = sizeof(char);
  2009. break;
  2010. case GV_DATETIME:
  2011. Mem->Size = sizeof(GDateTime);
  2012. break;
  2013. case GV_HASHTABLE:
  2014. Mem->Size = sizeof(GHashTable);
  2015. break;
  2016. case GV_OPERATOR:
  2017. Mem->Size = sizeof(GOperator);
  2018. break;
  2019. case GV_GMOUSE:
  2020. Mem->Size = sizeof(GMouse);
  2021. break;
  2022. case GV_GKEY:
  2023. Mem->Size = sizeof(GKey);
  2024. break;
  2025. case GV_CUSTOM:
  2026. Mem->Size = Mem->Nest->Sizeof();
  2027. break;
  2028. default:
  2029. return OnError(Cur, "Can't have non-pointer of type '%s'", TypeName.Str());
  2030. }
  2031. }
  2032. if (Mem->Array)
  2033. {
  2034. Mem->Size *= Mem->Array;
  2035. }
  2036. Def->Size += Mem->Size;
  2037. Def->Members.Add(Name.Str(), Mem);
  2038. t = GetTok(Cur);
  2039. if (StricmpW(t, sSemiColon))
  2040. return OnError(Cur, "Expecting ';'");
  2041. Cur++;
  2042. }
  2043. return Status;
  2044. EofError:
  2045. return OnError(Cur, "Unexpected EOF.");
  2046. }
  2047. bool DoExtern(int &Cur)
  2048. {
  2049. return false;
  2050. }
  2051. /// Compiler entry point
  2052. bool Compile()
  2053. {
  2054. int Cur = 0;
  2055. int JumpLoc = 0;
  2056. // Setup the global scope
  2057. Scopes.Length(0);
  2058. Scopes.Add(&Code->Globals);
  2059. // Compile the code...
  2060. while (Cur < Tokens.Length())
  2061. {
  2062. char16 *t = GetTok(Cur);
  2063. if (!t)
  2064. break;
  2065. if (*t == '#' ||
  2066. StricmpW(t, sSemiColon) == 0)
  2067. {
  2068. Cur++;
  2069. }
  2070. else if (!StricmpW(t, sFunction))
  2071. {
  2072. if (!JumpLoc)
  2073. {
  2074. int Len = Code->ByteCode.Length();
  2075. if (Code->ByteCode.Length(Len + 5))
  2076. {
  2077. GPtr p;
  2078. p.u8 = &Code->ByteCode[Len];
  2079. *p.u8++ = IJump;
  2080. *p.i32++ = 0;
  2081. JumpLoc = Len + 1;
  2082. }
  2083. else OnError(Cur, "Mem alloc failed.");
  2084. }
  2085. if (!DoFunction(++Cur))
  2086. return false;
  2087. }
  2088. else if (!StricmpW(t, sStruct))
  2089. {
  2090. if (!DoStruct(++Cur))
  2091. return false;
  2092. }
  2093. else if (!StricmpW(t, sEndCurlyBracket))
  2094. {
  2095. return OnError(Cur, "Not expecting '}'.");
  2096. }
  2097. else
  2098. {
  2099. if (JumpLoc)
  2100. {
  2101. GPtr p;
  2102. p.u8 = &Code->ByteCode[JumpLoc];
  2103. *p.u32 = Code->ByteCode.Length() - (JumpLoc + 4);
  2104. JumpLoc = 0;
  2105. }
  2106. if (!DoStatements(Cur))
  2107. {
  2108. return OnError(Cur, "Statement compilation failed.");
  2109. }
  2110. }
  2111. }

Large files files are truncated, but you can click here to view the full file