LLlex.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  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. * Author: Ceriel J.H. Jacobs
  6. */
  7. /* L E X I C A L A N A L Y S E R F O R M O D U L A - 2 */
  8. /* $Id$ */
  9. #include <alloc.h>
  10. #include "idfsize.h"
  11. #include "idf.h"
  12. #include "LLlex.h"
  13. #include "input.h"
  14. #include "f_info.h"
  15. #include "Lpars.h"
  16. #include "class.h"
  17. struct token dot,
  18. aside;
  19. int idfsize = IDFSIZE;
  20. int ForeignFlag;
  21. extern char *getwdir();
  22. static
  23. SkipComment()
  24. {
  25. /* Skip Modula-2 comments (* ... *).
  26. Note that comments may be nested (par. 3.5).
  27. */
  28. register int ch;
  29. register int CommentLevel = 0;
  30. LoadChar(ch);
  31. if (ch == '$') {
  32. LoadChar(ch);
  33. switch(ch) {
  34. case 'F':
  35. /* Foreign; This definition module has an
  36. implementation in another language.
  37. In this case, check that the object file is present
  38. and don't generate a rule for it.
  39. */
  40. ForeignFlag = 1;
  41. break;
  42. default:
  43. PushBack();
  44. break;
  45. }
  46. }
  47. for (;;) {
  48. if (class(ch) == STNL) {
  49. LineNumber++;
  50. }
  51. else if (ch == '(') {
  52. LoadChar(ch);
  53. if (ch == '*') CommentLevel++;
  54. else continue;
  55. }
  56. else if (ch == '*') {
  57. LoadChar(ch);
  58. if (ch == ')') {
  59. CommentLevel--;
  60. if (CommentLevel < 0) break;
  61. }
  62. else continue;
  63. }
  64. else if (ch == EOI) {
  65. lexerror("unterminated comment");
  66. break;
  67. }
  68. LoadChar(ch);
  69. }
  70. }
  71. static
  72. GetString(upto)
  73. {
  74. /* Read a Modula-2 string, delimited by the character "upto".
  75. */
  76. register int ch;
  77. while (LoadChar(ch), ch != upto) {
  78. if (class(ch) == STNL) {
  79. lexerror("newline in string");
  80. LineNumber++;
  81. break;
  82. }
  83. if (ch == EOI) {
  84. lexerror("end-of-file in string");
  85. break;
  86. }
  87. }
  88. }
  89. static char *s_error = "illegal line directive";
  90. static int
  91. getch()
  92. {
  93. register int ch;
  94. for (;;) {
  95. LoadChar(ch);
  96. if ((ch & 0200) && ch != EOI) {
  97. error("non-ascii '\\%03o' read", ch & 0377);
  98. continue;
  99. }
  100. break;
  101. }
  102. return ch;
  103. }
  104. CheckForLineDirective()
  105. {
  106. register int ch = getch();
  107. register int i = 0;
  108. char buf[IDFSIZE + 2];
  109. register char *c = buf;
  110. if (ch != '#') {
  111. PushBack();
  112. return;
  113. }
  114. do { /*
  115. * Skip to next digit
  116. * Do not skip newlines
  117. */
  118. ch = getch();
  119. if (class(ch) == STNL || class(ch) == STEOI) {
  120. LineNumber++;
  121. error(s_error);
  122. return;
  123. }
  124. } while (class(ch) != STNUM);
  125. while (class(ch) == STNUM) {
  126. i = i*10 + (ch - '0');
  127. ch = getch();
  128. }
  129. while (ch != '"' && class(ch) != STNL && class(ch) != STEOI)
  130. ch = getch();
  131. if (ch == '"') {
  132. c = buf;
  133. do {
  134. *c++ = ch = getch();
  135. if (class(ch) == STNL || class(ch) == STEOI) {
  136. LineNumber++;
  137. error(s_error);
  138. return;
  139. }
  140. } while (ch != '"');
  141. *--c = '\0';
  142. do {
  143. ch = getch();
  144. } while (class(ch) != STNL && class(ch) != STEOI);
  145. /*
  146. * Remember the file name
  147. */
  148. if (class(ch) == STNL && strcmp(FileName,buf)) {
  149. FileName = Salloc(buf,(unsigned) strlen(buf) + 1);
  150. WorkingDir = getwdir(FileName);
  151. }
  152. }
  153. if (class(ch) == STEOI) {
  154. error(s_error);
  155. return;
  156. }
  157. LineNumber = i;
  158. }
  159. char idfbuf[IDFSIZE + 2];
  160. int
  161. LLlex()
  162. {
  163. /* LLlex() is the Lexical Analyzer.
  164. The putting aside of tokens is taken into account.
  165. */
  166. register struct token *tk = &dot;
  167. register int ch, nch;
  168. if (ASIDE) { /* a token is put aside */
  169. *tk = aside;
  170. ASIDE = 0;
  171. return tk->tk_symb;
  172. }
  173. again:
  174. ch = getch();
  175. tk->tk_lineno = LineNumber;
  176. switch (class(ch)) {
  177. case STNL:
  178. LineNumber++;
  179. CheckForLineDirective();
  180. goto again;
  181. case STSKIP:
  182. goto again;
  183. case STGARB:
  184. if ((unsigned) ch - 040 < 0137) {
  185. lexerror("garbage char %c", ch);
  186. }
  187. else lexerror("garbage char \\%03o", ch);
  188. goto again;
  189. case STSIMP:
  190. if (ch == '(') {
  191. LoadChar(nch);
  192. if (nch == '*') {
  193. SkipComment();
  194. goto again;
  195. }
  196. PushBack();
  197. }
  198. if (ch == '&') return tk->tk_symb = AND;
  199. if (ch == '~') return tk->tk_symb = NOT;
  200. return tk->tk_symb = ch;
  201. case STCOMP:
  202. LoadChar(nch);
  203. switch (ch) {
  204. case '.':
  205. if (nch == '.') {
  206. return tk->tk_symb = UPTO;
  207. }
  208. break;
  209. case ':':
  210. if (nch == '=') {
  211. return tk->tk_symb = BECOMES;
  212. }
  213. break;
  214. case '<':
  215. if (nch == '=') {
  216. return tk->tk_symb = LESSEQUAL;
  217. }
  218. if (nch == '>') {
  219. return tk->tk_symb = '#';
  220. }
  221. break;
  222. case '>':
  223. if (nch == '=') {
  224. return tk->tk_symb = GREATEREQUAL;
  225. }
  226. break;
  227. default :
  228. crash("(LLlex, STCOMP)");
  229. }
  230. PushBack();
  231. return tk->tk_symb = ch;
  232. case STIDF:
  233. {
  234. register char *tag = &idfbuf[0];
  235. register struct idf *id;
  236. do {
  237. if (tag - idfbuf < idfsize) *tag++ = ch;
  238. LoadChar(ch);
  239. } while(in_idf(ch));
  240. PushBack();
  241. *tag++ = '\0';
  242. tk->TOK_IDF = id = findidf(idfbuf);
  243. return tk->tk_symb = id && id->id_reserved ? id->id_reserved : IDENT;
  244. }
  245. case STSTR:
  246. GetString(ch);
  247. return tk->tk_symb = STRING;
  248. case STNUM:
  249. {
  250. /* The problem arising with the "parsing" of a number
  251. is that we don't know the base in advance so we
  252. have to read the number with the help of a rather
  253. complex finite automaton.
  254. */
  255. enum statetp {Oct,OptHex,Hex,Dec,OctEndOrHex,End,OptReal,Real};
  256. register enum statetp state;
  257. state = is_oct(ch) ? Oct : Dec;
  258. LoadChar(ch);
  259. for (;;) {
  260. switch(state) {
  261. case Oct:
  262. while (is_oct(ch)) {
  263. LoadChar(ch);
  264. }
  265. if (ch == 'B' || ch == 'C') {
  266. state = OctEndOrHex;
  267. break;
  268. }
  269. /* Fall Through */
  270. case Dec:
  271. while (is_dig(ch)) {
  272. LoadChar(ch);
  273. }
  274. if (ch == 'D') state = OptHex;
  275. else if (is_hex(ch)) state = Hex;
  276. else if (ch == '.') state = OptReal;
  277. else {
  278. state = End;
  279. if (ch != 'H') PushBack();
  280. }
  281. break;
  282. case OptHex:
  283. LoadChar(ch);
  284. if (is_hex(ch)) {
  285. state = Hex;
  286. }
  287. else {
  288. ch = 'D';
  289. state = End;
  290. PushBack();
  291. }
  292. break;
  293. case Hex:
  294. while (is_hex(ch)) {
  295. LoadChar(ch);
  296. }
  297. state = End;
  298. if (ch != 'H') {
  299. lexerror("H expected after hex number");
  300. PushBack();
  301. }
  302. break;
  303. case OctEndOrHex:
  304. LoadChar(ch);
  305. if (ch == 'H') {
  306. state = End;
  307. break;
  308. }
  309. if (is_hex(ch)) {
  310. state = Hex;
  311. break;
  312. }
  313. PushBack();
  314. /* Fall through */
  315. case End:
  316. return tk->tk_symb = INTEGER;
  317. case OptReal:
  318. /* The '.' could be the first of the '..'
  319. token. At this point, we need a
  320. look-ahead of two characters.
  321. */
  322. LoadChar(ch);
  323. if (ch == '.') {
  324. /* Indeed the '..' token
  325. */
  326. PushBack();
  327. PushBack();
  328. state = End;
  329. break;
  330. }
  331. state = Real;
  332. break;
  333. }
  334. if (state == Real) break;
  335. }
  336. while (is_dig(ch)) {
  337. /* Fractional part
  338. */
  339. LoadChar(ch);
  340. }
  341. if (ch == 'E' || ch == 'D') {
  342. /* Scale factor
  343. */
  344. if (ch == 'D') {
  345. LoadChar(ch);
  346. if (!(ch == '+' || ch == '-' || is_dig(ch)))
  347. goto noscale;
  348. }
  349. LoadChar(ch);
  350. if (ch == '+' || ch == '-') {
  351. /* Signed scalefactor
  352. */
  353. LoadChar(ch);
  354. }
  355. if (is_dig(ch)) {
  356. do {
  357. LoadChar(ch);
  358. } while (is_dig(ch));
  359. }
  360. else {
  361. lexerror("bad scale factor");
  362. }
  363. }
  364. noscale:
  365. PushBack();
  366. return tk->tk_symb = REAL;
  367. /*NOTREACHED*/
  368. }
  369. case STEOI:
  370. return tk->tk_symb = -1;
  371. case STCHAR:
  372. default:
  373. crash("(LLlex) Impossible character class");
  374. /*NOTREACHED*/
  375. }
  376. /*NOTREACHED*/
  377. }