atop2.clu 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. % ATOP2 CLU
  2. %
  3. % CLUMAC assembler: top level
  4. _symbol = 0;
  5. _octal = 1;
  6. _decimal = 2;
  7. min_prec = 0;
  8. max_prec = 3;
  9. dm_lines = proc (e: env, fs: str);
  10. f: file := file$open_read(fs);
  11. except when open_failed: env$err(e, "couldn't open " || fs);
  12. return;
  13. end;
  14. e.input := f;
  15. while true do
  16. dm_line(e);
  17. k: int := scan_forward(e);
  18. if k = _eol
  19. then file$getc(f);
  20. elseif k = _eof
  21. then break;
  22. elseif k = _semi
  23. then file$gets(f, '\n');
  24. else env$err(e, "extraneous input: " || get_literal(e)); end;
  25. env$newline(e);
  26. end;
  27. file$close(f);
  28. end dm_lines;
  29. dm_line = proc (e: env);
  30. k: int := scan_forward(e);
  31. if k < _upper
  32. then return; end;
  33. sym: str, kind: int := get_idn(e);
  34. if kind ~= _symbol
  35. then env$err(e, "non-symbol for macro name: " || sym);
  36. return;
  37. end;
  38. k := scan_forward(e);
  39. mac: str;
  40. if k = _equal
  41. then file$getc(e.input);
  42. scan_forward(e);
  43. mac, kind := get_idn(e);
  44. if kind ~= _symbol
  45. then env$err(e, "non-symbol for macro definition: " || mac);
  46. mac := sym;
  47. end;
  48. else mac := "m_" || sym;
  49. end;
  50. v: any := value$id(mac);
  51. if value$is_none(v)
  52. then env$err(e, "undefined macro definition: " || mac);
  53. else env$defmac(e, sym, force[mtype](v));
  54. end;
  55. end dm_line;
  56. do_lines = proc (e: env, fs: str);
  57. f: file := file$open_read(fs);
  58. except when open_failed: env$err(e, "couldn't open " || fs);
  59. return;
  60. end;
  61. e.input := f;
  62. while true do
  63. do_line(e);
  64. k: int := scan_forward(e);
  65. if k = _eol
  66. then file$getc(f);
  67. elseif k = _eof
  68. then break;
  69. elseif k = _semi
  70. then file$gets(f, '\n');
  71. else env$err(e, "extraneous input: " || get_literal(e)); end;
  72. env$newline(e);
  73. end;
  74. file$close(f);
  75. end do_lines;
  76. do_line = proc (e: env);
  77. k: int := scan_forward(e);
  78. if k < _upper
  79. then return; end;
  80. sym: str, kind: int := get_idn(e);
  81. w: wrd := eval_idn(e, sym, kind);
  82. except when macro (m: mtype):
  83. f: file := e.input;
  84. if file$peek(f) ~= '\n'
  85. then file$getc(f); end;
  86. except when eof: ; end;
  87. m(e);
  88. return;
  89. end;
  90. k := scan_forward(e);
  91. if k = _equal cand kind = _symbol
  92. then file$getc(e.input);
  93. do_equate(e, sym);
  94. else env$err(e, "bad symbol begins line: " || sym);
  95. end;
  96. end do_line;
  97. do_equate = proc (e: env, sym: str);
  98. f: file := e.input;
  99. begin
  100. if file$peek(f) = '='
  101. then file$getc(f); end;
  102. if file$peek(f) = ':'
  103. then file$getc(f); end;
  104. w: wrd := get_expr(e);
  105. if e.lh_equate
  106. then w := wrd$r2l(w); end;
  107. env$define(e, sym, w);
  108. end;
  109. except when none, eof:
  110. env$err(e, "no expression on right side of equate");
  111. when macro:
  112. env$err(e, "equate to macro");
  113. end;
  114. end do_equate;
  115. scan_forward = proc (e: env) returns (int);
  116. f: file := e.input;
  117. ctab: ai := e.char_tab;
  118. while true do
  119. k: int := ctab[char$c2i(file$peek(f))];
  120. if k = _space
  121. then file$getc(f);
  122. else return(k);
  123. end;
  124. end;
  125. except when eof: return(_eof); end;
  126. end scan_forward;
  127. get_idn = proc (e: env) returns (str, int) signals (none);
  128. f: file := e.input;
  129. ctab: ai := e.char_tab;
  130. a: ac := e.temp_ac;
  131. kind: int := _octal;
  132. while true do
  133. c: char := file$peek(f);
  134. i: int := char$c2i(c);
  135. k: int := ctab[i];
  136. if k = _upper
  137. then c := char$i2c(i + 32);
  138. kind := _symbol;
  139. elseif k = _lower
  140. then if c = '.' cand kind = _octal cand ac$size(a) > 0
  141. then kind := _decimal;
  142. else kind := _symbol;
  143. end;
  144. elseif k < _upper
  145. then break; end;
  146. ac$addh(a, c);
  147. file$getc(f);
  148. end;
  149. except when eof: ; end;
  150. if kind = _decimal
  151. then ac$remh(a); end;
  152. s: str := str$ac2s(a);
  153. if s = ""
  154. then signal none; end;
  155. return(s, kind);
  156. end get_idn;
  157. get_literal = proc (e: env) returns (str);
  158. f: file := e.input;
  159. a: ac := e.temp_ac;
  160. while file$peek(f) ~= '\n' do
  161. ac$addh(a, file$getc(f));
  162. end;
  163. except when eof: ; end;
  164. return(str$ac2s(a));
  165. end get_literal;
  166. get_symbol = proc (e: env) returns (str);
  167. return(get_symbol1(e));
  168. except when none: return(""); end;
  169. end get_symbol;
  170. get_symbol1 = proc (e: env) returns (str) signals (none);
  171. f: file := e.input;
  172. ctab: ai := e.char_tab;
  173. a: ac := e.temp_ac;
  174. while true do
  175. c: char := file$peek(f);
  176. i: int := char$c2i(c);
  177. k: int := ctab[i];
  178. if k > _upper
  179. then
  180. elseif k = _upper
  181. then c := char$i2c(i + 32);
  182. elseif k = _comma
  183. then file$getc(f);
  184. break;
  185. elseif k = _semi
  186. then while ac$size(a) > 0 do
  187. c := ac$top(a);
  188. if c = ' ' cor c = '\t'
  189. then ac$remh(a);
  190. else return(str$ac2s(a));
  191. end;
  192. end;
  193. signal none;
  194. elseif k < _space cor k = _badch cor k = _rbkt
  195. then break; end;
  196. ac$addh(a, c);
  197. file$getc(f);
  198. end;
  199. except when eof: ; end;
  200. return(str$ac2s(a));
  201. end get_symbol1;
  202. get_symbols = iter (e: env) yields (str);
  203. f: file := e.input;
  204. if file$peek(f) ~= '['
  205. then yield(get_symbol1(e));
  206. return;
  207. end;
  208. except when eof, none: return; end;
  209. file$getc(f);
  210. while true do
  211. c: char := file$peek(f);
  212. if c = ']'
  213. then file$getc(f);
  214. if file$peek(f) = ','
  215. then file$getc(f); end;
  216. except when eof: ; end;
  217. break;
  218. elseif c = '\n'
  219. then exit eof; end;
  220. yield(get_symbol1(e));
  221. end;
  222. except when eof, none: env$err(e, "missing ] in symbol list"); end;
  223. end get_symbols;
  224. get_wrd = proc (e: env) returns (wrd);
  225. w: wrd := get_expr(e);
  226. except when none: w := wrd$create(0, 0); end;
  227. f: file := e.input;
  228. if file$peek(f) = ','
  229. then file$getc(f);
  230. except when eof: ; end;
  231. end;
  232. return(w);
  233. end get_wrd;
  234. get_wrds = iter (e: env) yields (wrd);
  235. f: file := e.input;
  236. if file$peek(f) ~= '['
  237. then yield(get_expr(e));
  238. if file$peek(f) = ','
  239. then file$getc(f); end;
  240. return;
  241. end;
  242. except when eof, none: return; end;
  243. file$getc(f);
  244. scan_forward(e);
  245. while true do
  246. c: char := file$peek(f);
  247. if c = ']'
  248. then file$getc(f);
  249. if file$peek(f) = ','
  250. then file$getc(f); end;
  251. break;
  252. elseif c = '\n'
  253. then env$err(e, "missing ] in symbol list");
  254. break;
  255. end;
  256. yield(get_wrd(e));
  257. end;
  258. except when eof: ; end;
  259. end get_wrds;
  260. get_number = proc (e: env) returns (int);
  261. left, right: int := wrd$w2i(get_expr(e));
  262. if left > 0
  263. then env$err(e, "number exceeds 18 bits"); end;
  264. return(right);
  265. end get_number;
  266. get_numbers = iter (e: env) yields (int);
  267. for w: wrd in get_wrds(e) do
  268. left, right: int := wrd$w2i(w);
  269. if left > 0
  270. then env$err(e, "number exceeds 18 bits"); end;
  271. yield(right);
  272. end;
  273. end get_numbers;
  274. get_value = proc (e: env) returns (wrd);
  275. % THIS IS INCOMPLETE !
  276. return(get_expr(e));
  277. except when none: return(wrd$create(0, 0)); end;
  278. end get_value;
  279. get_expr = proc (e: env) returns (wrd) signals (none);
  280. scan_forward(e);
  281. w: wrd := get_expr1(e, min_prec);
  282. except when none: signal none; end;
  283. while true do
  284. scan_forward(e);
  285. w := w + get_expr1(e, min_prec);
  286. end;
  287. except when none: ; end;
  288. return(w);
  289. end get_expr;
  290. get_expr1 = proc (e: env, prec: int) returns (wrd) signals (none);
  291. w: wrd := get_prim(e);
  292. except when none: signal none; end;
  293. f: file := e.input;
  294. while true do
  295. c: char := file$peek(f);
  296. if c = '+' cor c = '-'
  297. then if prec > 1
  298. then break; end;
  299. elseif c = '*'
  300. then if prec > 2
  301. then break; end;
  302. elseif ~(c = '&' cor c = '\\')
  303. then break; end;
  304. file$getc(f);
  305. right: wrd := get_expr1(e, prec);
  306. except when none: env$err(e, str$append("missing expression after ",
  307. c));
  308. break;
  309. end;
  310. if c = '+'
  311. then w := w + right;
  312. elseif c = '-'
  313. then w := w - right;
  314. elseif c = '*'
  315. then w := w * right;
  316. elseif c = '&'
  317. then w := w & right;
  318. else w := w | right; end;
  319. end;
  320. except when eof: ; end;
  321. return(w);
  322. end get_expr1;
  323. get_prim = proc (e: env) returns (wrd) signals (none);
  324. f: file := e.input;
  325. c: char := file$peek(f);
  326. except when eof: signal none; end;
  327. if c = '('
  328. then return(get_pexpr(e)); end;
  329. if c = '<'
  330. then return(get_aexpr(e)); end;
  331. if c = '-'
  332. then return(- get_prim(e));
  333. except when none: env$err(e, "missing expression after -");
  334. return(wrd$create(0, 0));
  335. end;
  336. end;
  337. sym: str, kind: int := get_idn(e);
  338. except when none: signal none; end;
  339. return(eval_idn(e, sym, kind));
  340. except when macro (*): ; end;
  341. env$err(e, "macro used in expression: " || sym);
  342. return(wrd$create(0, 0));
  343. end get_prim;
  344. get_pexpr = proc (e: env) returns (wrd);
  345. f: file := e.input;
  346. if file$eof(f) cor file$peek(f) ~= '('
  347. then env$err(e, "OOPS: get_pexpr couldn't find a left parenthesis");
  348. return(wrd$create(0, 0));
  349. end;
  350. file$getc(f);
  351. w: wrd := get_value(e);
  352. if file$eof(f) cor file$peek(f) ~= ')'
  353. then env$err(e, "missing right parenthesis in expression");
  354. else file$getc(f);
  355. end;
  356. return(wrd$swap(w));
  357. end get_pexpr;
  358. get_aexpr = proc (e: env) returns (wrd);
  359. f: file := e.input;
  360. if file$eof(f) cor file$peek(f) ~= '<'
  361. then env$err(e, "OOPS: get_pexpr couldn't find a left angle");
  362. return(wrd$create(0, 0));
  363. end;
  364. file$getc(f);
  365. w: wrd := get_value(e);
  366. if file$eof(f) cor file$peek(f) ~= '>'
  367. then env$err(e, "missing right angle in expression");
  368. else file$getc(f);
  369. end;
  370. return(w);
  371. end get_aexpr;
  372. eval_idn = proc (e: env, sym: str, kind: int) returns (wrd) signals (macro(mtype));
  373. if kind = _symbol
  374. then tagcase env$dlookup(e, sym)
  375. tag value, undef (w: wrd):
  376. return(w);
  377. tag macro (m: mtype):
  378. signal macro(m);
  379. end;
  380. end;
  381. if kind = _decimal
  382. then return(wrd$dparse(sym));
  383. else return(wrd$parse(sym));
  384. end;
  385. except when overflow: ; end;
  386. which: str;
  387. if kind = _decimal
  388. then which := "decimal value overflowed: ";
  389. else which := "octal value overflowed: ";
  390. end;
  391. env$err(e, which || sym);
  392. return(wrd$create(0, 0));
  393. end eval_idn;
  394.