LLlex.c 7.1 KB

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