LLlex.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375
  1. /*
  2. * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
  3. * See the copyright notice in the ACK home directory, in the file "Copyright".
  4. */
  5. /* $Id$ */
  6. /* L E X I C A L A N A L Y Z E R */
  7. #include "idfsize.h"
  8. #include "numsize.h"
  9. #include "strsize.h"
  10. #include <alloc.h>
  11. #include "input.h"
  12. #include "idf.h"
  13. #include "LLlex.h"
  14. #include "Lpars.h"
  15. #include "class.h"
  16. #include "bits.h"
  17. /* Data about the token yielded */
  18. struct token dot;
  19. int ReplaceMacros = 1; /* replacing macros */
  20. int AccFileSpecifier = 0; /* return filespecifier <...> */
  21. int AccDefined = 0; /* accept "defined(...)" */
  22. int UnknownIdIsZero = 0; /* interpret unknown id as integer 0 */
  23. char *string_token();
  24. char *strcpy();
  25. PushLex()
  26. {
  27. DOT = 0;
  28. }
  29. PopLex()
  30. {}
  31. int
  32. LLlex()
  33. {
  34. return (DOT != EOF) ? GetToken(&dot) : EOF;
  35. }
  36. #define BUFSIZ 1024
  37. int
  38. GetToken(ptok)
  39. register struct token *ptok;
  40. {
  41. char buf[BUFSIZ];
  42. register int c, nch;
  43. again: /* rescan the input after an error or replacement */
  44. LoadChar(c);
  45. if ((c & 0200) && c != EOI)
  46. fatal("non-ascii '\\%03o' read", c & 0377);
  47. switch (class(c)) { /* detect character class */
  48. case STNL:
  49. LineNumber++;
  50. return ptok->tk_symb = EOF;
  51. case STSKIP:
  52. goto again;
  53. case STGARB: /* garbage character */
  54. if (c == '\\') {
  55. /* a '\\' is allowed in #if/#elif expression */
  56. LoadChar(c);
  57. if (class(c) == STNL) { /* vt , ff ? */
  58. ++LineNumber;
  59. goto again;
  60. }
  61. PushBack();
  62. c = '\\';
  63. }
  64. if (040 < c && c < 0177)
  65. error("garbage char %c", c);
  66. else
  67. error("garbage char \\%03o", c);
  68. goto again;
  69. case STSIMP: /* a simple character, no part of compound token*/
  70. if (c == '/') { /* probably the start of comment */
  71. LoadChar(c);
  72. if (c == '*') { /* start of comment */
  73. skipcomment();
  74. goto again;
  75. }
  76. else {
  77. PushBack();
  78. c = '/'; /* restore c */
  79. }
  80. }
  81. return ptok->tk_symb = c;
  82. case STCOMP: /* maybe the start of a compound token */
  83. LoadChar(nch); /* character lookahead */
  84. switch (c) {
  85. case '!':
  86. if (nch == '=')
  87. return ptok->tk_symb = NOTEQUAL;
  88. PushBack();
  89. return ptok->tk_symb = c;
  90. case '&':
  91. if (nch == '&')
  92. return ptok->tk_symb = AND;
  93. PushBack();
  94. return ptok->tk_symb = c;
  95. case '<':
  96. if (AccFileSpecifier) {
  97. PushBack(); /* pushback nch */
  98. ptok->tk_str =
  99. string_token("file specifier", '>');
  100. return ptok->tk_symb = FILESPECIFIER;
  101. }
  102. if (nch == '<')
  103. return ptok->tk_symb = LEFT;
  104. if (nch == '=')
  105. return ptok->tk_symb = LESSEQ;
  106. PushBack();
  107. return ptok->tk_symb = c;
  108. case '=':
  109. if (nch != '=') {
  110. PushBack();
  111. error("missing =");
  112. }
  113. return ptok->tk_symb = EQUAL;
  114. case '>':
  115. if (nch == '=')
  116. return ptok->tk_symb = GREATEREQ;
  117. if (nch == '>')
  118. return ptok->tk_symb = RIGHT;
  119. PushBack();
  120. return ptok->tk_symb = c;
  121. case '|':
  122. if (nch == '|')
  123. return ptok->tk_symb = OR;
  124. PushBack();
  125. return ptok->tk_symb = c;
  126. }
  127. case STIDF:
  128. {
  129. extern int idfsize; /* ??? */
  130. register char *tg = &buf[0];
  131. register char *maxpos = &buf[idfsize];
  132. register struct idf *idef;
  133. #define tstmac(bx) if (!(bits[c] & bx)) goto nomac
  134. #define cpy if (Unstacked) EnableMacros(); *tg++ = c
  135. #define load LoadChar(c); if (!in_idf(c)) goto endidf
  136. #ifdef DOBITS
  137. cpy; tstmac(bit0); load;
  138. cpy; tstmac(bit1); load;
  139. cpy; tstmac(bit2); load;
  140. cpy; tstmac(bit3); load;
  141. cpy; tstmac(bit4); load;
  142. cpy; tstmac(bit5); load;
  143. cpy; tstmac(bit6); load;
  144. cpy; tstmac(bit7); load;
  145. #endif
  146. for(;;) {
  147. if (tg < maxpos) {
  148. cpy;
  149. }
  150. load;
  151. }
  152. endidf:
  153. PushBack();
  154. *tg = '\0'; /* mark the end of the identifier */
  155. if (ReplaceMacros) {
  156. idef = findidf(buf);
  157. if ((idef && idef->id_macro && replace(idef))) {
  158. goto again;
  159. }
  160. }
  161. nomac:
  162. LoadChar(c);
  163. while (in_idf(c)) {
  164. if (tg < maxpos) *tg++ = c;
  165. LoadChar(c);
  166. }
  167. PushBack();
  168. *tg++ = '\0'; /* mark the end of the identifier */
  169. if (UnknownIdIsZero) {
  170. ptok->tk_val = 0;
  171. return ptok->tk_symb = INTEGER;
  172. }
  173. ptok->tk_str = Malloc(tg - buf);
  174. strcpy(ptok->tk_str, buf);
  175. return ptok->tk_symb = IDENTIFIER;
  176. }
  177. case STCHAR: /* character constant */
  178. {
  179. register arith val = 0;
  180. register int size = 0;
  181. LoadChar(c);
  182. if (c == '\'')
  183. error("character constant too short");
  184. else
  185. while (c != '\'') {
  186. if (c == '\n') {
  187. error("newline in character constant");
  188. PushBack();
  189. break;
  190. }
  191. if (c == '\\') {
  192. LoadChar(c);
  193. if (c == '\n') {
  194. LineNumber++;
  195. }
  196. c = quoted(c);
  197. }
  198. if (c >= 128) c -= 256;
  199. val = val*256 + c;
  200. size++;
  201. LoadChar(c);
  202. }
  203. if (size > sizeof(arith))
  204. error("character constant too long");
  205. ptok->tk_val = val;
  206. return ptok->tk_symb = INTEGER;
  207. }
  208. case STNUM:
  209. {
  210. register char *np = &buf[1];
  211. register int base = 10;
  212. register int vch;
  213. register arith val = 0;
  214. if (c == '0') {
  215. *np++ = c;
  216. LoadChar(c);
  217. if (c == 'x' || c == 'X') {
  218. base = 16;
  219. LoadChar(c);
  220. }
  221. else
  222. base = 8;
  223. }
  224. while (vch = val_in_base(c, base), vch >= 0) {
  225. val = val*base + vch;
  226. if (np < &buf[NUMSIZE])
  227. *np++ = c;
  228. LoadChar(c);
  229. }
  230. if (c == 'l' || c == 'L')
  231. LoadChar(c);
  232. PushBack();
  233. ptok->tk_val = val;
  234. return ptok->tk_symb = INTEGER;
  235. }
  236. case STSTR:
  237. ptok->tk_str = string_token("string", '"');
  238. return ptok->tk_symb = STRING;
  239. case STEOI: /* end of text on source file */
  240. return ptok->tk_symb = EOF;
  241. default:
  242. crash("Impossible character class");
  243. }
  244. /*NOTREACHED*/
  245. }
  246. skipcomment()
  247. {
  248. register int c;
  249. NoUnstack++;
  250. LoadChar(c);
  251. do {
  252. while (c != '*') {
  253. if (class(c) == STNL)
  254. ++LineNumber;
  255. else
  256. if (c == EOI) {
  257. NoUnstack--;
  258. return;
  259. }
  260. LoadChar(c);
  261. }
  262. /* Last Character seen was '*' */
  263. LoadChar(c);
  264. } while (c != '/');
  265. NoUnstack--;
  266. }
  267. char *
  268. string_token(nm, stop_char)
  269. char *nm;
  270. {
  271. register int c;
  272. register unsigned int str_size;
  273. register char *str = Malloc(str_size = ISTRSIZE);
  274. register int pos = 0;
  275. LoadChar(c);
  276. while (c != stop_char) {
  277. if (c == '\n') {
  278. error("newline in %s", nm);
  279. PushBack();
  280. break;
  281. }
  282. if (c == EOI) {
  283. error("end-of-file inside %s", nm);
  284. break;
  285. }
  286. if (c == '\\') {
  287. LoadChar(c);
  288. if (c == '\n') {
  289. LineNumber++;
  290. LoadChar(c);
  291. continue;
  292. }
  293. c = quoted(c);
  294. }
  295. str[pos++] = c;
  296. if (pos == str_size)
  297. str = Realloc(str, str_size <<= 1);
  298. LoadChar(c);
  299. }
  300. str[pos++] = '\0'; /* for filenames etc. */
  301. str = Realloc(str, pos);
  302. return str;
  303. }
  304. int
  305. quoted(c)
  306. register int c;
  307. {
  308. /* quoted() replaces an escaped character sequence by the
  309. character meant.
  310. */
  311. /* first char after backslash already in c */
  312. if (!is_oct(c)) { /* a quoted char */
  313. switch (c) {
  314. case 'n':
  315. c = '\n';
  316. break;
  317. case 't':
  318. c = '\t';
  319. break;
  320. case 'b':
  321. c = '\b';
  322. break;
  323. case 'r':
  324. c = '\r';
  325. break;
  326. case 'f':
  327. c = '\f';
  328. break;
  329. }
  330. }
  331. else { /* a quoted octal */
  332. register int oct = 0, cnt = 0;
  333. do {
  334. oct = oct*8 + (c-'0');
  335. LoadChar(c);
  336. } while (is_oct(c) && ++cnt < 3);
  337. PushBack();
  338. c = oct;
  339. }
  340. return c&0377;
  341. }
  342. /* provisional */
  343. int
  344. val_in_base(c, base)
  345. register int c;
  346. {
  347. return
  348. is_dig(c) ? c - '0' :
  349. base != 16 ? -1 :
  350. is_hex(c) ? (c - 'a' + 10) & 017 :
  351. -1;
  352. }