context.js 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551
  1. var Cast = require("cast.js");
  2. var Code = require("code.js");
  3. var Errors = require("errors.js");
  4. var Lexer = require("lexer.js");
  5. var Module = require("module.js");
  6. var Parser = require("parser.js");
  7. var Procedure = require("procedure.js");
  8. var ImportRTL = require("rtl.js");
  9. var Stream = require("stream.js").Stream;
  10. var Type = require("type.js");
  11. var RTL = ImportRTL.RTL;
  12. var Class = ImportRTL.Class;
  13. var basicTypes = Type.basic;
  14. var Symbol = Type.Symbol;
  15. function getSymbol(context, id){
  16. var s = context.findSymbol(id);
  17. if (!s)
  18. throw new Errors.Error("undeclared identifier: '" + id + "'");
  19. return s;
  20. }
  21. function checkTypeCast(from, to, msg){
  22. if (from instanceof Type.Pointer)
  23. from = from.baseType();
  24. var t = to.baseType();
  25. while (t && t != from)
  26. t = t.baseType();
  27. if (!t)
  28. throw new Errors.Error(msg + ": '" + to.description()
  29. + "' is not an extension of '" + from.description() + "'");
  30. }
  31. var ChainedContext = Class.extend({
  32. init: function ChainedContext(parent){this.__parent = parent;},
  33. parent: function(){return this.__parent;},
  34. codeGenerator: function(){return this.__parent.codeGenerator();},
  35. findSymbol: function(id){return this.__parent.findSymbol(id);},
  36. addSymbol: function(s){this.__parent.addSymbol(s);},
  37. currentScope: function(s){return this.__parent.currentScope();},
  38. pushScope: function(){this.__parent.pushScope();},
  39. popScope: function(){this.__parent.popScope();},
  40. setType: function(type){this.__parent.setType(type);},
  41. setDesignator: function(d){this.__parent.setDesignator(d);},
  42. handleExpression: function(type, value, designator){this.__parent.handleExpression(type, value, designator);},
  43. handleLiteral: function(s){this.__parent.handleLiteral(s);},
  44. handleConst: function(type, value){this.__parent.handleConst(type, value);},
  45. genTypeName: function(){return this.__parent.genTypeName();},
  46. genVarName: function(id){return this.__parent.genVarName(id);},
  47. rtl: function(){return this.__parent.rtl();}
  48. });
  49. exports.Integer = ChainedContext.extend({
  50. init: function IntegerContext(context){
  51. ChainedContext.prototype.init.bind(this)(context);
  52. this.__result = "";
  53. this.__isHex = false;
  54. },
  55. isLexem: function(){return true;},
  56. handleChar: function(c){this.__result += c;},
  57. handleLiteral: function(){this.__isHex = true;},
  58. toInt: function(s){return parseInt(this.__result);},
  59. endParse: function(){
  60. var n = this.toInt();
  61. this.parent().codeGenerator().write(n.toString());
  62. this.parent().handleConst(basicTypes.int, n);
  63. }
  64. });
  65. exports.HexInteger = exports.Integer.extend({
  66. init: function HexIntegerContext(context){
  67. exports.Integer.prototype.init.bind(this)(context);
  68. },
  69. toInt: function(s){return parseInt(this.__result, 16);}
  70. });
  71. exports.Real = ChainedContext.extend({
  72. init: function RealContext(context){
  73. ChainedContext.prototype.init.bind(this)(context);
  74. this.__result = "";
  75. },
  76. isLexem: function(){return true;},
  77. handleChar: function(c){this.__result += c;},
  78. handleLiteral: function(s){
  79. if (s == "D") // LONGREAL
  80. s = "E";
  81. this.__result += s;
  82. },
  83. endParse: function(){
  84. var n = Number(this.__result);
  85. this.parent().codeGenerator().write(n.toString());
  86. this.parent().handleConst(basicTypes.real, n);
  87. }
  88. });
  89. function escapeString(s){
  90. var result = "\"";
  91. for(var i = 0; i < s.length; ++i){
  92. var c = s[i];
  93. if (c == '"')
  94. result += "\\\"";
  95. else
  96. result += s[i];
  97. }
  98. return result + "\"";
  99. }
  100. exports.String = ChainedContext.extend({
  101. init: function StringContext(context){
  102. ChainedContext.prototype.init.bind(this)(context);
  103. this.__result = "";
  104. },
  105. handleChar: function(c){this.__result += c;},
  106. toStr: function(s){return s;},
  107. endParse: function(){
  108. var s = this.toStr(this.__result);
  109. this.parent().codeGenerator().write(escapeString(s));
  110. this.parent().handleConst(new Type.String(s), s);
  111. }
  112. });
  113. exports.Char = exports.String.extend({
  114. init: function CharContext(context){
  115. exports.String.prototype.init.bind(this)(context);
  116. this.__result = "";
  117. },
  118. toStr: function(s){return String.fromCharCode(parseInt(s, 16));}
  119. });
  120. exports.BaseType = ChainedContext.extend({
  121. init: function BaseTypeContext(context){
  122. ChainedContext.prototype.init.bind(this)(context);
  123. },
  124. setIdent: function(id){this.parent().setBaseType(id);}
  125. });
  126. var DesignatorInfo = Class.extend({
  127. init: function(code, refCode, type, info){
  128. this.__code = code;
  129. this.__refCode = refCode;
  130. this.__type = type;
  131. this.__info = info;
  132. },
  133. code: function(){return this.__code;},
  134. refCode: function(){return this.__refCode(this.__code);},
  135. type: function(){return this.__type;},
  136. info: function(){return this.__info;}
  137. });
  138. exports.Designator = ChainedContext.extend({
  139. init: function DesignatorContext(context){
  140. ChainedContext.prototype.init.bind(this)(context);
  141. this.__currentType = undefined;
  142. this.__info = undefined;
  143. this.__code = new Code.SimpleGenerator();
  144. this.__derefCode = undefined;
  145. this.__propCode = undefined;
  146. },
  147. setIdent: function(id){
  148. var t = this.__currentType;
  149. if ( t === undefined){
  150. var s = getSymbol(this.parent(), id);
  151. var info = s.info();
  152. if (s.isType())
  153. this.__currentType = info;
  154. else if (s.isVariable() || s.isConst() || s.isProcedure()){
  155. this.__currentType = info.type();
  156. }
  157. else
  158. throw new Errors.Error("variable, constant or procedure name expected");
  159. this.__info = info;
  160. }
  161. else if (t instanceof Type.Pointer){
  162. this.__handleDeref();
  163. this.__denote(id);
  164. }
  165. else if (!(t instanceof Type.Record)
  166. && !(t instanceof Module.Type)
  167. && !(t instanceof Module.AnyType))
  168. throw new Errors.Error("cannot designate '" + t.description() + "'");
  169. else
  170. this.__denote(id);
  171. this.__code.write(id);
  172. },
  173. codeGenerator: function(){return this.__code;},
  174. handleExpression: function(expType, value, designator){
  175. if (expType != basicTypes.int)
  176. throw new Errors.Error("'INTEGER' expression expected, got '" + expType.name() + "'");
  177. var type = this.__currentType;
  178. if (!(type instanceof Type.Array))
  179. throw new Errors.Error("ARRAY expected, got '" + type.name() + "'");
  180. if (value !== undefined && value >= type.arraySize())
  181. throw new Errors.Error("index out of bounds: maximum possible index is "
  182. + (type.arraySize() - 1)
  183. + ", got " + value );
  184. this.__currentType = type.elementsType();
  185. this.__info = new Type.Variable(this.__currentType, false, this.__info.isReadOnly());
  186. if (designator)
  187. writeDerefDesignatorCode(designator, this.__code);
  188. },
  189. handleLiteral: function(s){
  190. if (s == "]" || s == ","){
  191. var indexCode = this.__code.result();
  192. this.__propCode = indexCode;
  193. this.__code = new Code.SimpleGenerator(this.__derefCode + "[" + indexCode + "]");
  194. }
  195. if (s == "[" || s == ","){
  196. this.__derefCode = this.__code.result();
  197. this.__code = new Code.SimpleGenerator();
  198. }
  199. else if (s == "^")
  200. this.__handleDeref();
  201. },
  202. __handleDeref: function(){
  203. if (!(this.__currentType instanceof Type.Pointer))
  204. throw new Errors.Error("POINTER TO type expected, got '"
  205. + this.__currentType.description() + "'");
  206. this.__currentType = this.__currentType.baseType();
  207. this.__info = new Type.Variable(this.__currentType, false, false);
  208. },
  209. handleTypeCast: function(type){
  210. if (!(type instanceof Type.Record))
  211. throw new Errors.Error(
  212. "invalid type cast: RECORD type expected as an argument of type guard, got '"
  213. + type.description() + "'");
  214. checkTypeCast(this.__currentType, type, "invalid type cast");
  215. var code = this.rtl().genCast(this.__code.result(), type);
  216. this.__code = new Code.SimpleGenerator(code);
  217. if (this.__currentType instanceof Type.Pointer)
  218. type = new Type.Pointer(this.genTypeName(), type);
  219. this.__currentType = type;
  220. },
  221. __denote: function(id){
  222. var t = this.__currentType;
  223. var fieldType = t.findSymbol(id);
  224. if (!fieldType)
  225. throw new Errors.Error("Type '" + t.name() + "' has no '" + id + "' field");
  226. this.__derefCode = this.__code.result();
  227. this.__propCode = "\"" + id + "\"";
  228. this.__code.write(".");
  229. this.__currentType = fieldType;
  230. },
  231. endParse: function(){
  232. var code = this.__code.result();
  233. this.parent().setDesignator(
  234. new DesignatorInfo(code, this.__makeRefCode.bind(this), this.__currentType, this.__info));
  235. },
  236. __makeRefCode: function(code){
  237. if (this.__derefCode)
  238. return this.rtl().makeRef(this.__derefCode, this.__propCode);
  239. if (!(this.__currentType instanceof Type.Array)
  240. && this.__info instanceof Type.Variable && !this.__info.isVar())
  241. return "{set: function($v){" + code + " = $v;}, get: function(){return " + code + ";}}";
  242. return code;
  243. }
  244. });
  245. exports.Type = ChainedContext.extend({
  246. init: function TypeContext(context){ChainedContext.prototype.init.bind(this)(context);},
  247. setIdent: function(id){
  248. var s = this.findSymbol(id);
  249. if (!s)
  250. throw new Errors.Error("undeclared type: '" + id + "'");
  251. if (s instanceof Type.Type)
  252. throw new Errors.Error("type name expected");
  253. this.setType(s.info());
  254. }
  255. });
  256. exports.FormalType = exports.Type.extend({
  257. init: function FormatlTypeContext(context){
  258. exports.Type.prototype.init.bind(this)(context);
  259. this.__arrayDimension = 0;
  260. },
  261. setType: function(type){
  262. for(var i = 0; i < this.__arrayDimension; ++i)
  263. type = new Type.Array("ARRAY OF " + type.name()
  264. , undefined
  265. , type);
  266. this.parent().setType(type);
  267. },
  268. handleLiteral: function(s){
  269. if (s == "ARRAY")
  270. ++this.__arrayDimension;
  271. }
  272. });
  273. var ProcArg = Class.extend({
  274. init: function(type, isVar){
  275. this.type = type;
  276. this.isVar = isVar;
  277. },
  278. description: function(){
  279. return (this.isVar ? "VAR " : "") + this.type.description();
  280. }
  281. });
  282. exports.FormalParameters = ChainedContext.extend({
  283. init: function FormalParametersContext(context){
  284. ChainedContext.prototype.init.bind(this)(context);
  285. this.__arguments = [];
  286. this.__result = undefined;
  287. var parent = this.parent();
  288. this.__type = new Procedure.Type(parent.typeName());
  289. parent.setType(this.__type);
  290. },
  291. addArgument: function(name, arg){
  292. this.__arguments.push(arg);
  293. },
  294. setIdent: function(id){
  295. var parent = this.parent();
  296. var s = getSymbol(parent, id);
  297. if (!s.isType())
  298. throw new Errors.Error("type name expected");
  299. this.__result = s.info();
  300. },
  301. endParse: function(){
  302. this.__type.define(this.__arguments, this.__result);
  303. }
  304. });
  305. exports.FormalParametersProcDecl = exports.FormalParameters.extend({
  306. init: function FormalParametersProcDeclContext(context){
  307. exports.FormalParameters.prototype.init.bind(this)(context);
  308. },
  309. addArgument: function(name, arg){
  310. exports.FormalParameters.prototype.addArgument.bind(this)(name, arg);
  311. this.parent().addArgument(name, arg);
  312. },
  313. endParse: function(){
  314. exports.FormalParameters.prototype.endParse.bind(this)();
  315. this.parent().endParameters();
  316. }
  317. });
  318. exports.ProcDecl = ChainedContext.extend({
  319. init: function ProcDeclContext(context){
  320. ChainedContext.prototype.init.bind(this)(context);
  321. this.__name = undefined;
  322. this.__firstArgument = true;
  323. this.__type = undefined;
  324. this.__returnParsed = false;
  325. this.__outerScope = this.parent().currentScope();
  326. },
  327. setIdent: function(id){
  328. var gen = this.codeGenerator();
  329. if (this.__name === undefined){ // first call
  330. this.__name = id;
  331. gen.write("\nfunction " + id + "(");
  332. this.parent().pushScope();
  333. }
  334. else if (this.__name === id){
  335. gen.closeScope();
  336. this.parent().popScope();
  337. }
  338. else
  339. throw new Errors.Error("mismatched procedure names: '" + this.__name
  340. + "' at the begining and '" + id + "' at the end");
  341. },
  342. typeName: function(){return undefined;},
  343. setType: function(type){
  344. var procSymbol = new Symbol(this.__name, new Type.Procedure(type));
  345. this.__outerScope.addSymbol(procSymbol);
  346. this.__type = type;
  347. },
  348. addArgument: function(name, arg){
  349. if (name == this.__name)
  350. throw new Errors.Error("argument '" + name + "' has the same name as procedure");
  351. var readOnly = !arg.isVar && (arg.type instanceof Type.Array);
  352. var s = new Symbol(name, new Type.Variable(arg.type, arg.isVar, readOnly));
  353. this.parent().addSymbol(s);
  354. var code = this.codeGenerator();
  355. if (!this.__firstArgument)
  356. code.write(", ");
  357. else
  358. this.__firstArgument = false;
  359. code.write(name + "/*" + arg.description() + "*/");
  360. },
  361. endParameters: function(){
  362. var code = this.codeGenerator();
  363. code.write(")");
  364. code.openScope();
  365. },
  366. handleReturn: function(type){
  367. var result = this.__type.result();
  368. if (!result)
  369. throw new Errors.Error("unexpected RETURN in PROCEDURE declared with no result type");
  370. if (!Cast.implicit(type, result))
  371. throw new Errors.Error(
  372. "RETURN '" + result.description() + "' expected, got '"
  373. + type.description() + "'");
  374. this.__returnParsed = true;
  375. },
  376. endParse: function(){
  377. var result = this.__type.result();
  378. if (result && !this.__returnParsed)
  379. throw new Errors.Error("RETURN expected at the end of PROCEDURE declared with '"
  380. + result.name() + "' result type");
  381. }
  382. });
  383. exports.Return = ChainedContext.extend({
  384. init: function ReturnContext(context){
  385. ChainedContext.prototype.init.bind(this)(context);
  386. this.__type = undefined;
  387. this.__code = new Code.SimpleGenerator();
  388. },
  389. codeGenerator: function(){return this.__code;},
  390. handleExpression: function(type, value, designator){
  391. this.__type = type;
  392. if (designator)
  393. writeDerefDesignatorCode(designator, this.__code);
  394. },
  395. endParse: function(){
  396. var parent = this.parent();
  397. parent.codeGenerator().write("return " + this.__code.result() + ";\n");
  398. parent.handleReturn(this.__type);
  399. }
  400. });
  401. exports.ProcParams = ChainedContext.extend({
  402. init: function ProcParamsContext(context){
  403. ChainedContext.prototype.init.bind(this)(context);
  404. this.__isVar = false;
  405. this.__argNamesForType = [];
  406. },
  407. handleLiteral: function(s){
  408. if (s == "VAR")
  409. this.__isVar = true;
  410. },
  411. setIdent: function(id){ this.__argNamesForType.push(id);},
  412. setType: function(type){
  413. var names = this.__argNamesForType;
  414. for(var i = 0; i < names.length; ++i){
  415. var name = names[i];
  416. this.parent().addArgument(name, new Procedure.Arg(type, this.__isVar));
  417. }
  418. this.__isVar = false;
  419. this.__argNamesForType = [];
  420. }
  421. });
  422. exports.PointerDecl = ChainedContext.extend({
  423. init: function PointerDeclContext(context){
  424. ChainedContext.prototype.init.bind(this)(context);
  425. this.__base = undefined;
  426. this.__name = this.parent().genTypeName();
  427. },
  428. setType: function(type){
  429. if (!(type instanceof Type.ForwardRecord) && !(type instanceof Type.Record))
  430. throw new Errors.Error(
  431. "RECORD is expected as a POINTER base type, got '" + type.description() + "'");
  432. this.__base = type;
  433. },
  434. findSymbol: function(id){
  435. var existing = this.parent().findSymbol(id);
  436. if (existing)
  437. return existing;
  438. var resolve = function(){return getSymbol(this.__parent, id).info();};
  439. return new Symbol(id, new Type.ForwardRecord(resolve.bind(this)));
  440. },
  441. genTypeName: function(){
  442. return this.__name + "$base";
  443. },
  444. endParse: function(){
  445. var type = new Type.Pointer(this.__name, this.__base);
  446. this.parent().setType(type);
  447. }
  448. });
  449. exports.ArrayDecl = ChainedContext.extend({
  450. init: function ArrayDeclContext(context){
  451. ChainedContext.prototype.init.bind(this)(context);
  452. this.__dimensions = undefined;
  453. },
  454. handleDimensions: function(dimensions){this.__dimensions = dimensions;},
  455. setType: function(type){
  456. var initializer = type instanceof Type.Array || type instanceof Type.Record
  457. ? "function(){return " + type.initializer() + ";}"
  458. : type.initializer();
  459. var dimensions = "";
  460. for(var i = 0; i < this.__dimensions.length; ++i){
  461. var length = this.__dimensions[i];
  462. dimensions += (dimensions.length ? ", " : "") + length;
  463. var arrayInit = i == this.__dimensions.length - 1
  464. ? this.rtl().makeArray(dimensions + ", " + initializer)
  465. : undefined;
  466. type = new Type.Array("ARRAY OF " + type.name()
  467. , arrayInit
  468. , type
  469. , length);
  470. }
  471. this.__type = type;
  472. },
  473. endParse: function(){this.parent().setType(this.__type);}
  474. });
  475. exports.ArrayDimensions = ChainedContext.extend({
  476. init: function ArrayDimensionsContext(context){
  477. ChainedContext.prototype.init.bind(this)(context);
  478. this.__dimensions = [];
  479. },
  480. codeGenerator: function(){return Code.nullGenerator;},
  481. handleExpression: function(type, value){
  482. if (type !== basicTypes.int)
  483. throw new Errors.Error("'INTEGER' constant expression expected, got '" + type.name() + "'");
  484. if (value === undefined)
  485. throw new Errors.Error("constant expression expected as ARRAY size");
  486. if (value <= 0)
  487. throw new Errors.Error("array size must be greater than 0, got " + value);
  488. this.__dimensions.push(value);
  489. },
  490. endParse: function(){
  491. this.parent().handleDimensions(this.__dimensions);
  492. }
  493. });
  494. exports.AddOperator = ChainedContext.extend({
  495. init: function AddOperatorContext(context){
  496. ChainedContext.prototype.init.bind(this)(context);
  497. },
  498. handleLiteral: function(s){
  499. var parent = this.parent();
  500. if (s == "+"){
  501. if (parent.type() == basicTypes.set){
  502. parent.handleBinaryOperator(function(x, y){return x | y;});
  503. parent.codeGenerator().write(" | ");
  504. }
  505. else {
  506. parent.handleBinaryOperator(function(x, y){return x + y;});
  507. parent.codeGenerator().write(" + ");
  508. }
  509. }
  510. else if (s == "-"){
  511. if (parent.type() == basicTypes.set){
  512. parent.handleBinaryOperator(function(x, y){return x & ~y;});
  513. parent.codeGenerator().write(" & ~");
  514. }
  515. else {
  516. parent.handleBinaryOperator(function(x, y){return x - y;});
  517. parent.codeGenerator().write(" - ");
  518. }
  519. }
  520. else if (s == "OR"){
  521. var type = parent.type();
  522. if (type != basicTypes.bool)
  523. throw new Errors.Error("BOOLEAN expected as operand of 'OR', got '"
  524. + type.name() + "'");
  525. parent.handleBinaryOperator(function(x, y){return x || y;});
  526. this.codeGenerator().write(" || ");
  527. }
  528. }
  529. });
  530. exports.MulOperator = ChainedContext.extend({
  531. init: function MulOperatorContext(context){
  532. ChainedContext.prototype.init.bind(this)(context);
  533. },
  534. handleLiteral: function(s){
  535. var parent = this.parent();
  536. if (s == "*")
  537. if (parent.type() == basicTypes.set)
  538. parent.handleOperator({
  539. eval: function(x, y){return x & y;}
  540. , code: function(x, y){return x + " & " + y;}
  541. });
  542. else
  543. parent.handleOperator({
  544. eval: function(x, y){return x * y;}
  545. , code: function(x, y){return x + " * " + y;}
  546. });
  547. else if (s == "/")
  548. if (parent.type() == basicTypes.set)
  549. parent.handleOperator({
  550. eval: function(x, y){return x ^ y;}
  551. , code: function(x, y){return x + " ^ " + y;}
  552. });
  553. else
  554. parent.handleOperator({
  555. eval: function(x, y){return x / y;}
  556. , code: function(x, y){return x + " / " + y;}
  557. });
  558. else if (s == "DIV")
  559. parent.handleOperator({
  560. eval: function(x, y){return (x / y) >> 0;}
  561. , code: function(x, y){return "(" + x + " / " + y + ") >> 0";}
  562. });
  563. else if (s == "MOD")
  564. parent.handleOperator({
  565. eval: function(x, y){return x % y;}
  566. , code: function(x, y){return x + " % " + y;}
  567. });
  568. else if (s == "&"){
  569. var type = parent.type();
  570. if (type != basicTypes.bool)
  571. throw new Errors.Error("BOOLEAN expected as operand of '&', got '"
  572. + type.name() + "'");
  573. parent.handleOperator({
  574. eval: function(x, y){return x && y;}
  575. , code: function(x, y){return x + " && " + y;}
  576. });
  577. }
  578. }
  579. });
  580. function writeDerefDesignatorCode(designator, code){
  581. var info = designator.info();
  582. if (info instanceof Type.Variable && info.isVar())
  583. code.write(".get()");
  584. }
  585. exports.Term = ChainedContext.extend({
  586. init: function TermContext(context){
  587. ChainedContext.prototype.init.bind(this)(context);
  588. this.__operator = undefined;
  589. this.__code = new Code.SimpleGenerator();
  590. this.__left = undefined;
  591. this.__isConst = true;
  592. this.__value = undefined;
  593. this.__designator = undefined;
  594. },
  595. codeGenerator: function(){return this.__code;},
  596. type: function(){return this.parent().type();},
  597. setDesignator: function(d){
  598. var type = d.type();
  599. this.parent().setType(type);
  600. var info = d.info();
  601. if (!(info instanceof Type.Const))
  602. this.__isConst = false;
  603. else
  604. this.handleConst(type, info.value());
  605. this.__code.write(d.code());
  606. this.__designator = d;
  607. if (this.__operator)
  608. this.__derefDesignator();
  609. },
  610. handleOperator: function(o){
  611. this.__derefDesignator();
  612. this.__left = this.__operator
  613. ? this.__operator.code(this.__left, this.__code.result())
  614. : this.__code.result();
  615. this.__operator = o;
  616. this.__code = new Code.SimpleGenerator();
  617. },
  618. handleConst: function(type, value){
  619. this.parent().setType(type);
  620. if (value === undefined)
  621. this.__isConst = false;
  622. else if (this.__isConst)
  623. this.__value = this.__operator ? this.__operator.eval(this.__value, value)
  624. : value;
  625. },
  626. procCalled: function(type){this.parent().procCalled(type);},
  627. endParse: function(){
  628. var code = this.__operator ? this.__operator.code(this.__left, this.__code.result())
  629. : this.__code.result();
  630. this.parent().handleTerm(
  631. code
  632. , this.__isConst ? this.__value : undefined
  633. , this.__operator ? undefined : this.__designator);
  634. },
  635. __derefDesignator: function(){
  636. var designator = this.__designator;
  637. if (!designator)
  638. return;
  639. writeDerefDesignatorCode(designator, this.__code);
  640. this.__designator = undefined;
  641. }
  642. });
  643. exports.Factor = ChainedContext.extend({
  644. init: function FactorContext(context){
  645. ChainedContext.prototype.init.bind(this)(context);
  646. },
  647. type: function(){return this.parent().type();},
  648. handleLiteral: function(s){
  649. var parent = this.parent();
  650. if (s == "NIL"){
  651. parent.handleConst(Type.nil, undefined);
  652. this.codeGenerator().write("null");
  653. }
  654. else if (s == "TRUE"){
  655. parent.handleConst(basicTypes.bool, true);
  656. this.codeGenerator().write("true");
  657. }
  658. else if (s == "FALSE"){
  659. parent.handleConst(basicTypes.bool, false);
  660. this.codeGenerator().write("false");
  661. }
  662. else if (s == "~"){
  663. parent.setType(basicTypes.bool);
  664. parent.handleOperator({
  665. eval: function(x, y){return !y;}
  666. , code: function(x, y){return "!" + y;}
  667. });
  668. }
  669. },
  670. procCalled: function(type){this.parent().procCalled(type);}
  671. });
  672. exports.Set = ChainedContext.extend({
  673. init: function SetContext(context){
  674. ChainedContext.prototype.init.bind(this)(context);
  675. this.__value = 0;
  676. this.__expr = "";
  677. },
  678. handleElement: function(from, fromValue, to, toValue){
  679. if (fromValue !== undefined && (!to || toValue !== undefined))
  680. if (to)
  681. for(var i = fromValue; i <= toValue; ++i)
  682. this.__value |= 1 << i;
  683. else
  684. this.__value |= 1 << fromValue;
  685. else{
  686. if (this.__expr.length)
  687. this.__expr += ", ";
  688. if (to)
  689. this.__expr += "[" + from + ", " + to + "]";
  690. else
  691. this.__expr += from;
  692. }
  693. },
  694. endParse: function(){
  695. var gen = this.codeGenerator();
  696. if (!this.__expr.length){
  697. gen.write(this.__value.toString());
  698. this.parent().handleConst(basicTypes.set, this.__value);
  699. }
  700. else{
  701. this.parent().setType(basicTypes.set);
  702. gen.write(this.rtl().makeSet(this.__expr));
  703. if (this.__value)
  704. gen.write(" | " + this.__value);
  705. }
  706. }
  707. });
  708. exports.SetElement = ChainedContext.extend({
  709. init: function SetElementContext(context){
  710. ChainedContext.prototype.init.bind(this)(context);
  711. this.__from = undefined;
  712. this.__fromValue = undefined;
  713. this.__to = undefined;
  714. this.__toValue = undefined;
  715. this.__expr = new Code.SimpleGenerator();
  716. },
  717. codeGenerator: function(){return this.__expr;},
  718. handleExpression: function(type, value){
  719. if (!this.__from)
  720. {
  721. this.__from = this.__expr.result();
  722. this.__fromValue = value;
  723. this.__expr = new Code.SimpleGenerator();
  724. }
  725. else{
  726. this.__to = this.__expr.result();
  727. this.__toValue = value;
  728. }
  729. },
  730. endParse: function(){
  731. this.parent().handleElement(this.__from, this.__fromValue, this.__to, this.__toValue);
  732. }
  733. });
  734. function constValueCode(value){
  735. if (typeof value == "string")
  736. return escapeString(value);
  737. return value.toString();
  738. }
  739. exports.SimpleExpression = ChainedContext.extend({
  740. init: function SimpleExpressionContext(context){
  741. ChainedContext.prototype.init.bind(this)(context);
  742. //this.__type = undefined;
  743. this.__binaryOperator = undefined;
  744. this.__unaryMinus = false;
  745. this.__unaryPlus = false;
  746. this.__isConst = true;
  747. this.__constValue = undefined;
  748. this.__designator = undefined;
  749. this.__code = new Code.SimpleGenerator();
  750. },
  751. codeGenerator: function(){return this.__code;},
  752. handleTerm: function(code, value, designator){
  753. if (value !== undefined)
  754. this.__handleConst(value);
  755. else
  756. this.__isConst = false;
  757. this.codeGenerator().write(code);
  758. this.__designator = designator;
  759. this.__derefDesignator();
  760. },
  761. handleLiteral: function(s){
  762. if (s == "-")
  763. this.__unaryMinus = true;
  764. else if (s == "+")
  765. this.__unaryPlus = true;
  766. },
  767. type: function(){return this.parent().type();},
  768. constValue: function(){return this.__isConst ? this.__constValue : undefined;},
  769. handleBinaryOperator: function(o){
  770. this.__binaryOperator = o;
  771. this.__derefDesignator();
  772. },
  773. handleUnaryOperator: function(o){
  774. this.__unary_operator = o;
  775. },
  776. procCalled: function(type){this.parent().procCalled(type);},
  777. endParse: function(){
  778. var parent = this.parent();
  779. var code = parent.codeGenerator();
  780. if (this.__unaryMinus)
  781. if (this.type() == basicTypes.set){
  782. if (this.__isConst)
  783. this.__constValue = ~this.__constValue;
  784. else
  785. code.write('~');
  786. }
  787. else {
  788. if (this.__isConst)
  789. this.__constValue = -this.__constValue;
  790. else
  791. code.write('-');
  792. }
  793. code.write(this.__isConst ? constValueCode(this.__constValue) : this.__code.result());
  794. parent.handleSimpleExpression(this.constValue(), this.__designator);
  795. },
  796. __handleConst: function(value){
  797. if (!this.__isConst)
  798. return;
  799. if (this.__unary_operator){
  800. value = this.__unary_operator(value);
  801. this.__unary_operator = undefined;
  802. }
  803. if (!this.__binaryOperator)
  804. this.__constValue = value;
  805. else
  806. this.__constValue = this.__binaryOperator(this.__constValue, value);
  807. },
  808. __derefDesignator: function(){
  809. if (!this.__designator)
  810. return;
  811. if (!this.__binaryOperator && !this.__unary_operator
  812. && !this.__unaryMinus && !this.__unaryPlus)
  813. return;
  814. writeDerefDesignatorCode(this.__designator, this.__code);
  815. this.__designator = undefined;
  816. }
  817. });
  818. exports.Expression = ChainedContext.extend({
  819. init: function ExpressionContext(context){
  820. ChainedContext.prototype.init.bind(this)(context);
  821. this.__leftParsed = false;
  822. this.__type = undefined;
  823. this.__relation = undefined;
  824. this.__value = undefined;
  825. this.__designator = undefined;
  826. this.__code = new Code.SimpleGenerator();
  827. },
  828. setType: function(type){
  829. if (this.__relation == "IS"){
  830. if (!(type instanceof Type.Record))
  831. throw new Errors.Error("RECORD type expected after 'IS'");
  832. checkTypeCast(this.__type, type, "invalid type test");
  833. }
  834. else if (type === undefined || this.__type === undefined)
  835. this.__type = type;
  836. else if (type !== this.__type)
  837. throw new Errors.Error("type mismatch: expected '" + this.__type.name()
  838. + "', got '" + type.name() + "'");
  839. },
  840. type: function(){return this.__type;},
  841. codeGenerator: function(){return this.__code;},
  842. handleSimpleExpression: function(value, designator){
  843. if (!this.__leftParsed){
  844. this.__leftParsed = true;
  845. this.__value = value;
  846. this.__designator = designator;
  847. }
  848. else {
  849. if (this.__relation == "IS"){
  850. if (!designator || !(designator.info() instanceof Type.Type))
  851. throw new Errors.Error("type name expected");
  852. }
  853. this.__type = basicTypes.bool;
  854. this.__value = undefined;
  855. this.__designator = undefined;
  856. }
  857. },
  858. procCalled: function(type){
  859. if (!type)
  860. throw new Errors.Error("procedure returning no result cannot be used in an expression");
  861. this.__type = type;
  862. this.__designator = undefined;
  863. },
  864. handleLiteral: function(relation){
  865. if (relation == "IS")
  866. if (!(this.__type instanceof Type.Pointer))
  867. throw new Errors.Error("POINTER to type expected before 'IS'");
  868. else
  869. this.codeGenerator().write(" instanceof ");
  870. else if (relation == "IN"){
  871. if (this.__type != basicTypes.int)
  872. throw new Errors.Error("'INTEGER' expected as an element of SET, got '" + this.__type.name() + "'");
  873. this.__type = basicTypes.set;
  874. this.__code = new Code.SimpleGenerator("1 << " + this.__code.result() + " & ");
  875. }
  876. else if (relation == "=")
  877. this.__code = new Code.SimpleGenerator(this.__code.result() + " == ");
  878. else if (relation == "#")
  879. this.__code = new Code.SimpleGenerator(this.__code.result() + " != ");
  880. else if (relation == "<=" || relation == ">=")
  881. this.__code.write(", ");
  882. this.__relation = relation;
  883. },
  884. endParse: function(){
  885. var parent = this.parent();
  886. var code = parent.codeGenerator();
  887. if (this.__relation == "<=")
  888. code.write(this.rtl().setInclL(this.__code.result()));
  889. else if (this.__relation == ">=")
  890. code.write(this.rtl().setInclR(this.__code.result()));
  891. else
  892. code.write(this.__code.result());
  893. parent.handleExpression(this.__type, this.__value, this.__designator);
  894. }
  895. });
  896. function handleIfExpression(type){
  897. if (type !== basicTypes.bool)
  898. throw new Errors.Error("'BOOLEAN' expression expected, got '" + type.name() + "'");
  899. }
  900. function endIfParse(){
  901. var gen = this.codeGenerator();
  902. gen.write(")");
  903. gen.openScope();
  904. }
  905. exports.If = ChainedContext.extend({
  906. init: function IfContext(context){
  907. ChainedContext.prototype.init.bind(this)(context);
  908. this.codeGenerator().write("if (");
  909. },
  910. handleExpression: handleIfExpression,
  911. endParse: endIfParse
  912. });
  913. exports.ElseIf = ChainedContext.extend({
  914. init: function ElseIfContext(context){
  915. ChainedContext.prototype.init.bind(this)(context);
  916. var gen = this.codeGenerator();
  917. gen.closeScope();
  918. gen.write("else if (");
  919. },
  920. handleExpression: handleIfExpression,
  921. endParse: endIfParse
  922. });
  923. exports.Else = ChainedContext.extend({
  924. init: function ElseContext(context){
  925. ChainedContext.prototype.init.bind(this)(context);
  926. var gen = this.codeGenerator();
  927. gen.closeScope();
  928. gen.write("else ");
  929. gen.openScope();
  930. }
  931. });
  932. exports.emitEndStatement = function(context){
  933. context.codeGenerator().write(";\n");
  934. };
  935. exports.emitIfEnd = function(context){
  936. context.codeGenerator().closeScope();
  937. };
  938. exports.Case = ChainedContext.extend({
  939. init: function CaseContext(context){
  940. ChainedContext.prototype.init.bind(this)(context);
  941. this.__type = undefined;
  942. this.__firstCase = true;
  943. this.genVarName("$c");
  944. this.codeGenerator().write("$c = ");
  945. },
  946. handleExpression: function(type){
  947. var gen = this.codeGenerator();
  948. if (type instanceof Type.String){
  949. var v = type.asChar();
  950. if (v !== undefined){
  951. gen.write(v);
  952. type = basicTypes.char;
  953. }
  954. }
  955. if (type != basicTypes.int && type != basicTypes.char)
  956. throw new Errors.Error("'INTEGER' or 'CHAR' expected as CASE expression");
  957. this.__type = type;
  958. gen.write(";\n");
  959. },
  960. beginCase: function(){
  961. if (this.__firstCase)
  962. this.__firstCase = false;
  963. else
  964. this.codeGenerator().write("else ");
  965. },
  966. handleLabelType: function(type){
  967. if (type !== this.__type)
  968. throw new Errors.Error(
  969. "label must be '" + this.__type.name() + "' (the same as case expression), got '"
  970. + type.name() + "'");
  971. }
  972. });
  973. exports.CaseLabelList = ChainedContext.extend({
  974. init: function CaseLabelListContext(context){
  975. ChainedContext.prototype.init.bind(this)(context);
  976. this.__glue = "";
  977. },
  978. handleLabelType: function(type){this.parent().handleLabelType(type);},
  979. handleRange: function(from, to){
  980. if (!this.__glue)
  981. this.parent().caseLabelBegin();
  982. var cond = to === undefined
  983. ? "$c === " + from
  984. : "($c >= " + from + " && $c <= " + to + ")";
  985. this.codeGenerator().write(this.__glue + cond);
  986. this.__glue = " || ";
  987. },
  988. endParse: function(){this.parent().caseLabelEnd();}
  989. });
  990. exports.CaseLabel = ChainedContext.extend({
  991. init: function CaseLabelContext(context){
  992. ChainedContext.prototype.init.bind(this)(context);
  993. },
  994. caseLabelBegin: function(){
  995. this.parent().beginCase();
  996. this.codeGenerator().write("if (");
  997. },
  998. caseLabelEnd: function(){
  999. var gen = this.codeGenerator();
  1000. gen.write(")");
  1001. gen.openScope();
  1002. },
  1003. handleLabelType: function(type){this.parent().handleLabelType(type);},
  1004. handleRange: function(from, to){this.parent().handleRange(from, to);},
  1005. endParse: function(){this.codeGenerator().closeScope();}
  1006. });
  1007. exports.CaseRange = ChainedContext.extend({
  1008. init: function CaseRangeContext(context){
  1009. ChainedContext.prototype.init.bind(this)(context);
  1010. this.__from = undefined;
  1011. this.__to = undefined;
  1012. },
  1013. codeGenerator: function(){return Code.nullGenerator;}, // suppress any output
  1014. handleLabel: function(type, v){
  1015. this.parent().handleLabelType(type);
  1016. if (this.__from === undefined )
  1017. this.__from = v;
  1018. else
  1019. this.__to = v;
  1020. },
  1021. handleConst: function(type, value){
  1022. if (type instanceof Type.String){
  1023. value = type.asChar();
  1024. if (value === undefined)
  1025. throw new Errors.Error("single-character string expected");
  1026. type = basicTypes.char;
  1027. }
  1028. this.handleLabel(type, value);
  1029. },
  1030. setIdent: function(id){
  1031. var s = getSymbol(this.parent(), id);
  1032. if (!s.isConst())
  1033. throw new Errors.Error("'" + id + "' is not a constant");
  1034. var type = s.info().type();
  1035. if (type instanceof Type.String)
  1036. this.handleConst(type, undefined);
  1037. else
  1038. this.handleLabel(type, s.info().value());
  1039. },
  1040. endParse: function(){this.parent().handleRange(this.__from, this.__to);}
  1041. });
  1042. exports.While = ChainedContext.extend({
  1043. init: function WhileContext(context){
  1044. ChainedContext.prototype.init.bind(this)(context);
  1045. var gen = this.codeGenerator();
  1046. gen.write("while (true)");
  1047. gen.openScope();
  1048. gen.write("if (");
  1049. },
  1050. handleExpression: handleIfExpression,
  1051. endParse: function(){
  1052. var gen = this.codeGenerator();
  1053. gen.write(")");
  1054. gen.openScope();
  1055. }
  1056. });
  1057. exports.emitWhileEnd = function(context){
  1058. var gen = context.codeGenerator();
  1059. gen.closeScope(" else break;\n");
  1060. gen.closeScope();
  1061. };
  1062. exports.Repeat = ChainedContext.extend({
  1063. init: function RepeatContext(context){
  1064. ChainedContext.prototype.init.bind(this)(context);
  1065. var gen = context.codeGenerator();
  1066. gen.write("do ");
  1067. gen.openScope();
  1068. }
  1069. });
  1070. exports.Until = ChainedContext.extend({
  1071. init: function UntilContext(context){
  1072. ChainedContext.prototype.init.bind(this)(context);
  1073. var gen = context.codeGenerator();
  1074. gen.closeScope(" while (");
  1075. },
  1076. handleExpression: handleIfExpression,
  1077. endParse: function(){this.codeGenerator().write(");\n");}
  1078. });
  1079. exports.For = ChainedContext.extend({
  1080. init: function ForContext(context){
  1081. ChainedContext.prototype.init.bind(this)(context);
  1082. this.__var = undefined;
  1083. this.__initExprParsed = false;
  1084. this.__toExpr = new Code.SimpleGenerator();
  1085. this.__toParsed = false;
  1086. this.__by_parsed = false;
  1087. this.__by = undefined;
  1088. },
  1089. setIdent: function(id){
  1090. var s = getSymbol(this.parent(), id);
  1091. if (!s.isVariable())
  1092. throw new Errors.Error("'" + s.id() + "' is not a variable");
  1093. if (s.info().type() !== basicTypes.int)
  1094. throw new Errors.Error(
  1095. "'" + s.id() + "' is a 'BOOLEAN' variable, 'FOR' control variable must be 'INTEGER'");
  1096. this.codeGenerator().write("for (" + id + " = ");
  1097. this.__var = id;
  1098. },
  1099. handleExpression: function(type, value){
  1100. if (type !== basicTypes.int)
  1101. throw new Errors.Error(
  1102. !this.__initExprParsed
  1103. ? "'INTEGER' expression expected to assign '" + this.__var
  1104. + "', got '" + type.name() + "'"
  1105. : !this.__toParsed
  1106. ? "'INTEGER' expression expected as 'TO' parameter, got '" + type.name() + "'"
  1107. : "'INTEGER' expression expected as 'BY' parameter, got '" + type.name() + "'"
  1108. );
  1109. if (!this.__initExprParsed)
  1110. this.__initExprParsed = true;
  1111. else if (!this.__toParsed)
  1112. this.__toParsed = true;
  1113. else if ( value === undefined )
  1114. throw new Errors.Error("constant expression expected as 'BY' parameter");
  1115. else
  1116. this.__by = value;
  1117. },
  1118. codeGenerator: function(){
  1119. if (this.__initExprParsed && !this.__toParsed)
  1120. return this.__toExpr;
  1121. if (this.__toParsed && !this.__by_parsed)
  1122. return Code.nullGenerator; // suppress output for BY expression
  1123. return this.parent().codeGenerator();
  1124. },
  1125. handleBegin: function(){
  1126. this.__by_parsed = true;
  1127. var relation = this.__by < 0 ? " >= " : " <= ";
  1128. var step = this.__by === undefined
  1129. ? "++" + this.__var
  1130. : this.__var + (this.__by < 0
  1131. ? " -= " + -this.__by
  1132. : " += " + this.__by);
  1133. var s = "; " + this.__var + relation + this.__toExpr.result() + "; " + step + ")";
  1134. var gen = this.codeGenerator();
  1135. gen.write(s);
  1136. gen.openScope();
  1137. },
  1138. endParse: function(){this.codeGenerator().closeScope();}
  1139. });
  1140. exports.emitForBegin = function(context){context.handleBegin();};
  1141. exports.Assignment = ChainedContext.extend({
  1142. init: function AssignmentContext(context){
  1143. ChainedContext.prototype.init.bind(this)(context);
  1144. this.__designator = undefined;
  1145. this.__leftOp = undefined;
  1146. this.__type = undefined;
  1147. },
  1148. setDesignator: function(d){
  1149. this.__designator = d;
  1150. },
  1151. handleLiteral: function(){
  1152. var d = this.__designator;
  1153. var d_info = d.info();
  1154. if (!(d_info instanceof Type.Variable) || d_info.isReadOnly())
  1155. throw new Errors.Error("cannot assign to " + d_info.idType());
  1156. this.__leftOp = d.code();
  1157. this.__type = d.type();
  1158. this.codeGenerator().write(this.__leftOp + (d_info.isVar() ? ".set(" : " = "));
  1159. },
  1160. handleExpression: function(type, value, designator){
  1161. if (!Cast.implicit(type, this.__type))
  1162. throw new Errors.Error("type mismatch: '" + this.__leftOp
  1163. + "' is '" + this.__type.description()
  1164. + "' and cannot be assigned to '" + type.description() + "' expression");
  1165. if (designator)
  1166. writeDerefDesignatorCode(designator, this.codeGenerator());
  1167. },
  1168. endParse: function(){
  1169. if (this.__designator.info().isVar())
  1170. this.codeGenerator().write(")");
  1171. }
  1172. });
  1173. exports.ConstDecl = ChainedContext.extend({
  1174. init: function ConstDeclContext(context){
  1175. ChainedContext.prototype.init.bind(this)(context);
  1176. this.__id = undefined;
  1177. this.__type = undefined;
  1178. this.__value = undefined;
  1179. },
  1180. setIdent: function(id){
  1181. this.__id = id;
  1182. this.codeGenerator().write("var " + id + " = ");
  1183. },
  1184. handleExpression: function(type, value){
  1185. if (value === undefined)
  1186. throw new Errors.Error("constant expression expected");
  1187. this.__type = type;
  1188. this.__value = value;
  1189. },
  1190. endParse: function(){
  1191. var c = new Type.Const(this.__type, this.__value);
  1192. this.addSymbol(new Symbol(this.__id, c));
  1193. this.codeGenerator().write(";\n");
  1194. }
  1195. });
  1196. exports.VariableDeclaration = ChainedContext.extend({
  1197. init: function VariableDeclarationContext(context){
  1198. ChainedContext.prototype.init.bind(this)(context);
  1199. this.__idents = [];
  1200. this.__type = undefined;
  1201. },
  1202. setIdent: function(id) {this.__idents.push(id);},
  1203. setType: function(type) {this.__type = type;},
  1204. typeName: function(){return undefined;},
  1205. endParse: function(){
  1206. var v = new Type.Variable(this.__type);
  1207. var idents = this.__idents;
  1208. var gen = this.codeGenerator();
  1209. for(var i = 0; i < idents.length; ++i)
  1210. {
  1211. var varName = idents[i];
  1212. this.addSymbol(new Symbol(varName, v));
  1213. var t = v.type();
  1214. gen.write("var " + varName + " = " + t.initializer() + ";");
  1215. }
  1216. gen.write("\n");
  1217. }
  1218. });
  1219. exports.FieldListDeclaration = ChainedContext.extend({
  1220. init: function FieldListDeclarationContext(context){
  1221. ChainedContext.prototype.init.bind(this)(context);
  1222. this.__idents = [];
  1223. this.__type = undefined;
  1224. },
  1225. setIdent: function(id) {this.__idents.push(id);},
  1226. setType: function(type) {this.__type = type;},
  1227. endParse: function(){
  1228. var idents = this.__idents;
  1229. for(var i = 0; i < idents.length; ++i){
  1230. var fieldName = idents[i];
  1231. var fieldType = this.__type;
  1232. this.parent().addField(fieldName, fieldType);
  1233. }
  1234. }
  1235. });
  1236. function assertProcType(type){
  1237. if (!(type instanceof Procedure.Type) && !(type instanceof Module.AnyType))
  1238. throw new Errors.Error("PROCEDURE expected, got '" + type.name() + "'");
  1239. }
  1240. exports.ActualParameters = ChainedContext.extend({
  1241. init: function ActualParametersContext(context){
  1242. ChainedContext.prototype.init.bind(this)(context);
  1243. this.parent().hasActualParameters();
  1244. },
  1245. });
  1246. exports.ProcedureCall = ChainedContext.extend({
  1247. init: function ProcedureCallContext(context){
  1248. ChainedContext.prototype.init.bind(this)(context);
  1249. this.__type = undefined;
  1250. this.__procCall = undefined;
  1251. this.__code = undefined;
  1252. },
  1253. setDesignator: function(d){
  1254. var type = d.type();
  1255. assertProcType(type);
  1256. this.__type = type;
  1257. this.__procCall = type.callGenerator(new Code.SimpleGenerator(), d.code());
  1258. this.__code = new Code.SimpleGenerator();
  1259. },
  1260. codeGenerator: function(){
  1261. return this.__code ? this.__code : this.parent().codeGenerator();
  1262. },
  1263. type: function(){return this.__type;},
  1264. setType: function(){},
  1265. hasActualParameters: function(){},
  1266. handleExpression: function(type, value, designator){
  1267. var code = this.__code.result();
  1268. this.__code = new Code.SimpleGenerator();
  1269. this.__procCall.handleArgument(type, designator, code);
  1270. },
  1271. endParse: function(){this.parent().codeGenerator().write(this.__procCall.end());}
  1272. });
  1273. exports.ExpressionProcedureCall = exports.ProcedureCall.extend({
  1274. init: function ExpressionProcedureCallContext(context){
  1275. exports.ProcedureCall.prototype.init.bind(this)(context);
  1276. this.__designator = undefined;
  1277. this.__hasActualParameters = false;
  1278. },
  1279. setDesignator: function(d){
  1280. this.__designator = d;
  1281. },
  1282. hasActualParameters: function(){
  1283. exports.ProcedureCall.prototype.setDesignator.bind(this)(this.__designator);
  1284. this.__hasActualParameters = true;
  1285. },
  1286. endParse: function(){
  1287. if (this.__hasActualParameters){
  1288. exports.ProcedureCall.prototype.endParse.bind(this)();
  1289. this.parent().procCalled(this.__type.result());
  1290. }
  1291. else
  1292. this.parent().setDesignator(this.__designator);
  1293. }
  1294. });
  1295. exports.RecordDecl = ChainedContext.extend({
  1296. init: function RecordDeclContext(context){
  1297. ChainedContext.prototype.init.bind(this)(context);
  1298. var id = this.genTypeName();
  1299. this.__type = new Type.Record(id);
  1300. var gen = this.codeGenerator();
  1301. gen.write("var " + id + " = ");
  1302. },
  1303. addField: function(name, type) {this.__type.addField(name, type);},
  1304. setBaseType: function(id){
  1305. var s = getSymbol(this.parent(), id);
  1306. if (!s.isType())
  1307. throw new Errors.Error("type name expected");
  1308. this.__type.setBaseType(s.info());
  1309. },
  1310. endParse: function(){
  1311. var type = this.__type;
  1312. var baseType = type.baseType();
  1313. var gen = this.codeGenerator();
  1314. gen.write((baseType ? baseType.name() : this.rtl().baseClass()) + ".extend(");
  1315. gen.openScope();
  1316. gen.write("init: function " + type.name() + "()");
  1317. gen.openScope();
  1318. if (baseType)
  1319. gen.write(baseType.name() + ".prototype.init.bind(this)();\n");
  1320. var ownFields = type.ownFields();
  1321. for(var f in ownFields)
  1322. gen.write("this." + f + " = " + ownFields[f].initializer() + ";\n");
  1323. this.parent().setType(type);
  1324. gen.closeScope();
  1325. gen.closeScope(");\n");
  1326. }
  1327. });
  1328. exports.TypeDeclaration = ChainedContext.extend({
  1329. init: function TypeDeclarationContext(context){
  1330. ChainedContext.prototype.init.bind(this)(context);
  1331. this.__id = undefined;
  1332. },
  1333. setIdent: function(id){this.__ident = id;},
  1334. setType: function(type){
  1335. this.addSymbol(new Symbol(this.__ident, type));
  1336. },
  1337. typeName: function(){return this.__ident;},
  1338. genTypeName: function(){return this.__ident;},
  1339. type: function(){return this.parent().type();}
  1340. });
  1341. exports.TypeCast = ChainedContext.extend({
  1342. init: function TypeCastContext(context){
  1343. ChainedContext.prototype.init.bind(this)(context);
  1344. this.__type = undefined;
  1345. },
  1346. setIdent: function(id){
  1347. var s = getSymbol(this.parent(), id);
  1348. if (!s.isType())
  1349. return; // this is not a type cast, may be procedure call
  1350. this.__type = s.info();
  1351. },
  1352. endParse: function(){
  1353. if (this.__type === undefined)
  1354. return false;
  1355. this.parent().handleTypeCast(this.__type);
  1356. return true;
  1357. }
  1358. });
  1359. exports.ModuleDeclaration = ChainedContext.extend({
  1360. init: function ModuleDeclarationContext(context){
  1361. ChainedContext.prototype.init.bind(this)(context);
  1362. this.__name = undefined;
  1363. },
  1364. setIdent: function(id){
  1365. var gen = this.codeGenerator();
  1366. if (this.__name === undefined ) {
  1367. this.__name = id;
  1368. this.addSymbol(new Symbol(id, Type.module));
  1369. gen.write("var " + id + " = function " + "(){\n");
  1370. }
  1371. else if (id === this.__name)
  1372. gen.write("}();");
  1373. else
  1374. throw new Errors.Error("original module name '" + this.__name + "' expected, got '" + id + "'" );
  1375. }
  1376. });
  1377. var ModuleImport = ChainedContext.extend({
  1378. init: function ModuleImport(context){
  1379. ChainedContext.prototype.init.bind(this)(context);
  1380. },
  1381. setIdent: function(id){
  1382. if (id == "JS"){
  1383. this.rtl().supportJS();
  1384. this.addSymbol(new Symbol("JS", new Module.JS()));
  1385. }
  1386. }
  1387. });
  1388. exports.ModuleImport = ModuleImport;
  1389. var Scope = Class.extend({
  1390. init: function Scope(){
  1391. var symbols = {};
  1392. for(var t in basicTypes){
  1393. var type = basicTypes[t];
  1394. symbols[type.name()] = new Symbol(type.name(), type);
  1395. }
  1396. symbols["LONGREAL"] = new Symbol("LONGREAL", basicTypes.real);
  1397. var predefined = Procedure.predefined;
  1398. for(var i = 0; i < predefined.length; ++i){
  1399. var s = predefined[i];
  1400. symbols[s.id()] = s;
  1401. }
  1402. this.__symbols = symbols;
  1403. },
  1404. addSymbol: function(symbol){
  1405. var id = symbol.id();
  1406. if (this.findSymbol(id))
  1407. throw new Errors.Error( "'" + id + "' already declared");
  1408. this.__symbols[id] = symbol;
  1409. },
  1410. findSymbol: function(ident){return this.__symbols[ident];}
  1411. });
  1412. exports.Context = Class.extend({
  1413. init: function Context(){
  1414. this.__code = new Code.Generator();
  1415. this.__designator = undefined;
  1416. this.__type = undefined;
  1417. this.__scopes = [new Scope()];
  1418. this.__gen = 0;
  1419. this.__vars = [];
  1420. this.__rtl = new RTL();
  1421. },
  1422. setDesignator: function(d){this.__designator = d;},
  1423. //designator: function(id){return this.__designator;},
  1424. type: function(){return this.__type;},
  1425. genTypeName: function(){
  1426. ++this.__gen;
  1427. return "anonymous$" + this.__gen;
  1428. },
  1429. genVarName: function(id){
  1430. if (this.__vars.indexOf(id) === -1) {
  1431. this.__code.write("var " + id + ";\n");
  1432. this.__vars.push(id);
  1433. }
  1434. },
  1435. addSymbol: function(symbol){this.currentScope().addSymbol(symbol);},
  1436. findSymbol: function(ident){
  1437. for(var i = this.__scopes.length; i--;){
  1438. var s = this.__scopes[i].findSymbol(ident);
  1439. if (s)
  1440. return s;
  1441. }
  1442. return undefined;
  1443. },
  1444. currentScope: function(){return this.__scopes[this.__scopes.length - 1];},
  1445. pushScope: function(){this.__scopes.push(new Scope());},
  1446. popScope: function(){this.__scopes.pop();},
  1447. handleExpression: function(){},
  1448. handleLiteral: function(){},
  1449. getResult: function(){
  1450. return this.__rtl.generate() + this.__code.getResult();
  1451. },
  1452. codeGenerator: function(){return this.__code;},
  1453. rtl: function(){
  1454. return this.__rtl;
  1455. }
  1456. });