read_em.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  1. /* $Header$ */
  2. /*
  3. * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
  4. * See the copyright notice in the ACK home directory, in the file "Copyright".
  5. */
  6. /* Read_em: a module to read either compact or human readable EM code.
  7. Exported are the following routines:
  8. EM_open() : has a parameter representing either a pointer to a
  9. filename or a null pointer, indicating that input is
  10. from standard input. This routine initializes for
  11. reading.
  12. EM_getinstr() : Delivers the next EM instruction in a format
  13. defined in <em_comp.h>.
  14. Imported are:
  15. The constants COMPACT (either defined or not defined) and
  16. CHECKING (again either defined or not defined),
  17. some routines from the system module. and the em_code module
  18. */
  19. #include <assert.h>
  20. #include <system.h>
  21. #include <em_label.h>
  22. #include <em_arith.h>
  23. #include <em_pseu.h>
  24. #include <em_spec.h>
  25. #include "em_ptyp.h"
  26. #include "em_comp.h"
  27. #include <em_flag.h>
  28. #include <em_mes.h>
  29. /* Buffered input */
  30. #define getbyte() (*_ich ? (*_ich++ & 0377) : _fill())
  31. #define ungetbyte(uch) ((uch) >= 0 && (*--_ich = (uch)))
  32. #define init_input() (_fill(), _ich--)
  33. #define EOF -1
  34. static File *fd;
  35. static char *_ich;
  36. PRIVATE int
  37. _fill()
  38. {
  39. static char text[BUFSIZ + 1];
  40. static int sz;
  41. if (_ich && _ich < &text[sz]) return _ich++, '\0';
  42. _ich = text;
  43. if (sys_read(fd, text, BUFSIZ, &sz) &&
  44. sz > 0
  45. ) {
  46. text[sz] = '\0';
  47. return (*_ich++&0377);
  48. }
  49. else {
  50. sz = 0;
  51. text[0] = 0;
  52. return EOF;
  53. }
  54. }
  55. #define NARGS 3 /* Maximum number of arguments */
  56. #define STRSIZ 256 /* Maximum length of strings */
  57. static struct e_instr emhead; /* Where we put the head */
  58. static struct e_args emargs[NARGS+2]; /* Where we put the arguments.
  59. We need some more because some
  60. arguments are constructed
  61. */
  62. static struct e_args *i_emargs;
  63. #define argentry() (i_emargs++)
  64. static struct string {
  65. int length;
  66. char str[STRSIZ + 1];
  67. } strings[NARGS]; /* Room for strings */
  68. static struct string *i_strings; /* Index of last one used */
  69. #define stringentry() (i_strings++)
  70. static struct e_args *argp; /* Indicates arguments yet to be
  71. delivered
  72. */
  73. static arith strleft; /* count # of chars left to read
  74. in a string
  75. */
  76. static int state; /* What state are we in? */
  77. #define CON 01 /* Reading a CON */
  78. #define ROM 02 /* Reading a ROM */
  79. #define MES 03 /* Reading a MES */
  80. #define PSEUMASK 03
  81. #define INSTRING 010 /* Reading a string */
  82. static int EM_initialized; /* EM_open called? */
  83. static long wordmask[] = { /* allowed bits in a word */
  84. 0x00000000,
  85. 0x000000FF,
  86. 0x0000FFFF,
  87. 0x00000000,
  88. 0xFFFFFFFF
  89. };
  90. static int wsize, psize; /* word size and pointer size */
  91. int EM_wordsize, EM_pointersize;
  92. #ifdef CHECKING
  93. static char *argrange = "Argument range error";
  94. #define check(expr) (expr || (xerror(argrange)))
  95. #else not CHECKING
  96. #define check(x) /* nothing */
  97. #endif CHECKING
  98. /* Error handling
  99. */
  100. PRIVATE
  101. xerror(s)
  102. char *s;
  103. {
  104. if (emhead.em_type != EM_FATAL) emhead.em_type = EM_ERROR;
  105. if (!EM_error) EM_error = s;
  106. }
  107. PRIVATE
  108. xfatal(s)
  109. char *s;
  110. {
  111. emhead.em_type = EM_FATAL;
  112. if (!EM_error) EM_error = s;
  113. }
  114. #ifdef COMPACT
  115. #include "readk.c"
  116. #else not COMPACT
  117. #include "reade.c"
  118. #endif COMPACT
  119. /* EM_open: Open input file, get magic word if COMPACT.
  120. */
  121. EXPORT int
  122. EM_open(filename)
  123. char *filename;
  124. {
  125. if (EM_initialized) {
  126. EM_error = "EM_open already called";
  127. return 0;
  128. }
  129. if (filename) {
  130. if (!sys_open(filename, OP_READ, &fd)) {
  131. EM_error = "Could not open input file";
  132. return 0;
  133. }
  134. }
  135. else fd = STDIN;
  136. EM_filename = filename;
  137. init_input();
  138. #ifdef COMPACT
  139. if (get16() != sp_magic) {
  140. EM_error = "Illegal magic word";
  141. return 0;
  142. }
  143. #else not COMPACT
  144. inithash(); /* initialize hashtable */
  145. #endif COMPACT
  146. EM_initialized = 1;
  147. return 1;
  148. }
  149. /* EM_close: Close input file
  150. */
  151. EXPORT
  152. EM_close()
  153. {
  154. register struct string *pstr;
  155. if (fd != STDIN) {
  156. sys_close(fd);
  157. fd = STDIN;
  158. }
  159. EM_initialized = 0;
  160. }
  161. /* startmes: handle the start of a message. The only important thing here
  162. is to get the wordsize and pointer size, and remember that they
  163. have already been read, not only to check that they are not specified
  164. again, but also to deliver the arguments on next calls to EM_getinstr.
  165. This is indicated by the variable "argp".
  166. */
  167. PRIVATE
  168. startmes(p)
  169. register struct e_instr *p;
  170. {
  171. register struct e_args *ap;
  172. ap = getarg(cst_ptyp);
  173. p->em_arg = ap;
  174. state = MES;
  175. if (ap->em_cst == ms_emx) {
  176. if (wsize || psize) {
  177. xerror("Duplicate ms_emx");
  178. }
  179. argp = ap = getarg(cst_ptyp);
  180. wsize = ap->em_cst;
  181. EM_wordsize = ap->em_cst;
  182. ap->em_next = getarg(cst_ptyp);
  183. ap = ap->em_next;
  184. psize = ap->em_cst;
  185. EM_pointersize = ap->em_cst;
  186. }
  187. }
  188. /* EM_getinstr: read an "EM_line"
  189. */
  190. EXPORT struct e_instr *
  191. EM_getinstr()
  192. {
  193. register struct e_instr *p = &emhead;
  194. register struct e_args *args;
  195. i_emargs = emargs;
  196. i_strings = strings;
  197. EM_error = 0;
  198. #ifdef CHECKING
  199. if (!EM_initialized) {
  200. EM_error = "Initialization not done";
  201. p->em_type = EM_FATAL;
  202. return p;
  203. }
  204. #endif CHECKING
  205. if (argp) { /* We have some arguments left to deliver */
  206. args = argp;
  207. argp = args->em_next;
  208. p->em_type = EM_MESARG;
  209. p->em_arg = args;
  210. args->em_next = 0;
  211. return p;
  212. }
  213. if (!state) { /* All clear, get a new line */
  214. p = gethead();
  215. if (!p) { /* End of file */
  216. return p;
  217. }
  218. switch(p->em_type) {
  219. case EM_MNEM: {
  220. register int i,j;
  221. register struct e_args *ap;
  222. extern char em_flag[];
  223. extern short em_ptyp[];
  224. p->em_args = 0;
  225. j = em_flag[p->em_opcode - sp_fmnem] & EM_PAR;
  226. i = em_ptyp[j];
  227. if (j == PAR_NO) { /* No arguments */
  228. break;
  229. }
  230. #ifndef COMPACT
  231. if (j == PAR_B) i = ptyp(sp_ilb2);
  232. #endif COMPACT
  233. ap = getarg(i);
  234. #ifndef COMPACT
  235. if (j == PAR_B) {
  236. ap->em_cst = ap->em_ilb;
  237. ap->em_argtype = cst_ptyp;
  238. }
  239. #endif COMPACT
  240. /* range checking
  241. */
  242. #ifdef CHECKING
  243. if (wsize <= 4 && psize <= 4) switch(j) {
  244. case PAR_B:
  245. check(ap->em_cst <= 32767);
  246. /* Fall through */
  247. case PAR_N:
  248. check(ap->em_cst >= 0);
  249. break;
  250. case PAR_G:
  251. if (ap->em_argtype == cst_ptyp) {
  252. check(ap->em_cst >= 0);
  253. }
  254. /* Fall through */
  255. case PAR_F:
  256. /* ??? not in original em_decode or em_encode */
  257. case PAR_L:
  258. { arith m = ap->em_cst >= 0 ? ap->em_cst :
  259. - ap->em_cst;
  260. /* Check that the number fits in a pointer */
  261. check((m & ~wordmask[psize]) == 0);
  262. break;
  263. }
  264. case PAR_W:
  265. if (!ap) break;
  266. check((ap->em_cst & ~wordmask[wsize]) == 0);
  267. /* Fall through */
  268. case PAR_S:
  269. check(ap->em_cst > 0);
  270. /* Fall through */
  271. case PAR_Z:
  272. check(ap->em_cst >= 0 &&
  273. ap->em_cst % wsize == 0);
  274. break;
  275. case PAR_O:
  276. check(ap->em_cst > 0 &&
  277. ( ap->em_cst % wsize == 0 ||
  278. wsize % ap->em_cst == 0));
  279. break;
  280. case PAR_R:
  281. check(ap->em_cst >= 0 && ap->em_cst <= 2);
  282. break;
  283. }
  284. #endif CHECKING
  285. p->em_args = ap;
  286. #ifndef COMPACT
  287. checkeol();
  288. #endif COMPACT
  289. }
  290. break;
  291. case EM_PSEU:
  292. /* handle a pseudo, read possible arguments. CON's and
  293. ROM's are handled especially: Only one argument is
  294. read, and a mark is set that an argument list of
  295. type ROM or CON is in process
  296. */
  297. {
  298. register struct e_args *ap = 0, *ap1;
  299. switch(p->em_opcode) {
  300. case ps_bss:
  301. case ps_hol:
  302. ap = getarg(cst_ptyp);
  303. ap->em_next = ap1 = getarg(par_ptyp);
  304. ap->em_next->em_next = ap1 = getarg(cst_ptyp);
  305. #ifdef CHECKING
  306. /* Check that the last value is 0 or 1
  307. */
  308. if (ap1->em_cst != 1 && ap1->em_cst != 0) {
  309. xerror("Third argument of hol/bss not 0/1");
  310. }
  311. #endif CHECKING
  312. break;
  313. case ps_exa:
  314. case ps_ina:
  315. ap = getarg(lab_ptyp);
  316. break;
  317. case ps_exp:
  318. case ps_inp:
  319. ap = getarg(pro_ptyp);
  320. break;
  321. case ps_exc:
  322. ap = getarg(cst_ptyp);
  323. ap->em_next = getarg(cst_ptyp);
  324. break;
  325. case ps_pro:
  326. ap = getarg(pro_ptyp);
  327. ap->em_next = getarg(cst_ptyp|ptyp(sp_cend));
  328. break;
  329. case ps_end:
  330. ap = getarg(cst_ptyp|ptyp(sp_cend));
  331. break;
  332. case ps_con:
  333. ap = getarg(val_ptyp);
  334. state |= CON;
  335. break;
  336. case ps_rom:
  337. ap = getarg(val_ptyp);
  338. state |= ROM;
  339. break;
  340. default:
  341. xerror("Bad pseudo");
  342. break;
  343. }
  344. p->em_args = ap;
  345. }
  346. #ifndef COMPACT
  347. if (p->em_opcode != ps_con && p->em_opcode != ps_rom) {
  348. checkeol();
  349. }
  350. #endif COMPACT
  351. break;
  352. case EM_STARTMES:
  353. startmes(p);
  354. break;
  355. }
  356. if (!wsize) {
  357. xerror("EM code should start with mes 2");
  358. }
  359. if (EM_error && p->em_type != EM_FATAL) p->em_type = EM_ERROR;
  360. return p;
  361. }
  362. if (state & INSTRING) { /* We already delivered part of a string.
  363. Deliver the next part
  364. */
  365. register struct string *s;
  366. s = getstring(0);
  367. args = argentry();
  368. args->em_next = 0;
  369. args->em_argtype = str_ptyp;
  370. args->em_str = s->str;
  371. args->em_size = s->length;
  372. switch(state & PSEUMASK) {
  373. default:
  374. assert(0);
  375. case MES:
  376. xerror("String too long in message");
  377. /* p->em_type = EM_MESARG;
  378. p->em_arg = args;
  379. */
  380. break;
  381. case CON:
  382. p->em_type = EM_PSEU;
  383. p->em_opcode = ps_con;
  384. p->em_args = args;
  385. break;
  386. case ROM:
  387. p->em_type = EM_PSEU;
  388. p->em_opcode = ps_rom;
  389. p->em_args = args;
  390. break;
  391. }
  392. if (EM_error && p->em_type != EM_FATAL) p->em_type = EM_ERROR;
  393. return p;
  394. }
  395. /* Here, we are in a state reading arguments */
  396. args = getarg(any_ptyp);
  397. if (EM_error && p->em_type != EM_FATAL) {
  398. p->em_type = EM_ERROR;
  399. return p;
  400. }
  401. if (!args) { /* No more arguments */
  402. #ifndef COMPACT
  403. checkeol();
  404. #endif
  405. if (state == MES) {
  406. state = 0;
  407. p->em_type = EM_ENDMES;
  408. return p;
  409. }
  410. /* Here, we have to get the next instruction */
  411. state = 0;
  412. return EM_getinstr();
  413. }
  414. /* Here, there was an argument */
  415. if (state == MES) {
  416. p->em_type = EM_MESARG;
  417. p->em_arg = args;
  418. return p;
  419. }
  420. p->em_type = EM_PSEU;
  421. p->em_args = args;
  422. if (state == CON) p->em_opcode = ps_con;
  423. else p->em_opcode = ps_rom;
  424. return p;
  425. }