LLlex.c 7.1 KB

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