Lexer.ob 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. MODULE Lexer;
  2. IMPORT
  3. Chars, ContextExpression, ContextHierarchy, Errors, Stream, String;
  4. CONST
  5. doubleQuote = Chars.doubleQuote;
  6. commentBegin = "(*";
  7. commentEnd = "*)";
  8. TYPE
  9. Literal* = RECORD
  10. PROCEDURE Literal*(s: STRING);
  11. s: STRING
  12. END;
  13. PROCEDURE isDigit(c: CHAR): BOOLEAN;
  14. RETURN (c >= "0") & (c <= "9")
  15. END;
  16. PROCEDURE isLetter(c: CHAR): BOOLEAN;
  17. RETURN ((c >= "a") & (c <= "z")) OR ((c >= "A") & (c <= "Z"))
  18. END;
  19. PROCEDURE peekSeparator(VAR stream: Stream.Type): BOOLEAN;
  20. BEGIN
  21. result <- TRUE;
  22. IF ~Stream.eof(stream) THEN
  23. c <- Stream.peekChar(stream);
  24. IF isLetter(c) THEN
  25. result := FALSE;
  26. ELSIF c = "." THEN
  27. result := Stream.peekStr(stream, "..");
  28. END;
  29. END;
  30. RETURN result;
  31. END;
  32. PROCEDURE integer*(VAR stream: Stream.Type; VAR cx: ContextExpression.Integer): BOOLEAN;
  33. VAR
  34. hexDetected: BOOLEAN;
  35. dec, hex: INTEGER;
  36. PROCEDURE collect(c: CHAR): BOOLEAN;
  37. BEGIN
  38. d <- -1;
  39. IF isDigit(c) THEN
  40. d := ORD(c) - ORD("0");
  41. ELSIF (c >= "A") & (c <= "F") THEN
  42. d := ORD(c) - ORD("A") + 10;
  43. hexDetected := TRUE;
  44. END;
  45. IF d # -1 THEN
  46. hex := hex * 16 + d;
  47. IF ~hexDetected THEN
  48. dec := dec * 10 + d;
  49. END;
  50. END;
  51. RETURN d # -1;
  52. END;
  53. BEGIN
  54. result <- FALSE;
  55. IF ~Stream.eof(stream) & collect(Stream.getChar(stream)) & ~hexDetected THEN
  56. WHILE ~Stream.eof(stream) & collect(Stream.peekChar(stream)) DO
  57. Stream.next(stream, 1);
  58. END;
  59. IF ~Stream.eof(stream) & (Stream.peekChar(stream) = "H") THEN
  60. hexDetected := TRUE;
  61. Stream.next(stream, 1);
  62. ELSIF hexDetected THEN
  63. Errors.raise("integer constant looks like having hexadecimal format but 'H' suffix is missing");
  64. END;
  65. IF peekSeparator(stream) THEN
  66. IF hexDetected THEN
  67. cx.handleInt(hex);
  68. ELSE
  69. cx.handleInt(dec);
  70. END;
  71. result := TRUE;
  72. END;
  73. END
  74. RETURN result;
  75. END;
  76. PROCEDURE real*(VAR stream: Stream.Type; VAR cx: ContextExpression.Real): BOOLEAN;
  77. VAR
  78. c: CHAR;
  79. s: STRING;
  80. PROCEDURE peekChar(): BOOLEAN;
  81. BEGIN
  82. result <- FALSE;
  83. IF ~Stream.eof(stream) THEN
  84. c := Stream.peekChar(stream);
  85. result := TRUE;
  86. END;
  87. RETURN result;
  88. END;
  89. PROCEDURE getChar(): BOOLEAN;
  90. BEGIN
  91. result <- FALSE;
  92. IF ~Stream.eof(stream) THEN
  93. c := Stream.getChar(stream);
  94. result := TRUE;
  95. END;
  96. RETURN result;
  97. END;
  98. PROCEDURE next();
  99. BEGIN
  100. Stream.next(stream, 1);
  101. END;
  102. PROCEDURE collectOptionalDigits();
  103. BEGIN
  104. WHILE peekChar() & isDigit(c) DO
  105. s := s + String.fromChar(c);
  106. next();
  107. END;
  108. END;
  109. PROCEDURE collectDigits(): BOOLEAN;
  110. BEGIN
  111. result <- FALSE;
  112. IF getChar() & isDigit(c) THEN
  113. s := s + String.fromChar(c);
  114. collectOptionalDigits();
  115. result := TRUE;
  116. END;
  117. RETURN result;
  118. END;
  119. PROCEDURE collectScale(): BOOLEAN;
  120. PROCEDURE collectPlusOrMinus();
  121. BEGIN
  122. IF peekChar() THEN
  123. IF c = "-" THEN
  124. s := s + "-";
  125. next();
  126. ELSIF c = "+" THEN
  127. next();
  128. END;
  129. END;
  130. END;
  131. BEGIN
  132. result <- TRUE;
  133. IF peekChar() & (c = "E") THEN
  134. s := s + "E";
  135. next();
  136. collectPlusOrMinus();
  137. result := collectDigits();
  138. END;
  139. RETURN result;
  140. END;
  141. BEGIN
  142. result <- FALSE;
  143. IF collectDigits() & getChar() & (c = ".") THEN
  144. s := s + ".";
  145. collectOptionalDigits();
  146. IF collectScale() & peekSeparator(stream) THEN
  147. cx.handleReal(String.parseReal(s));
  148. result := TRUE;
  149. END
  150. END;
  151. RETURN result;
  152. END;
  153. PROCEDURE isHexDigit(c: CHAR): BOOLEAN;
  154. RETURN isDigit(c) OR ((c >= "A") & (c <= "F"));
  155. END;
  156. PROCEDURE point*(VAR stream: Stream.Type; context: ContextHierarchy.Node): BOOLEAN;
  157. VAR result: BOOLEAN;
  158. BEGIN
  159. IF ~Stream.eof(stream)
  160. & (Stream.getChar(stream) = ".")
  161. & ( Stream.eof(stream)
  162. OR (Stream.peekChar(stream) # ".")) THEN (*not a diapason ".."*)
  163. context.handleLiteral(".");
  164. result := TRUE;
  165. END
  166. RETURN result;
  167. END;
  168. PROCEDURE string*(VAR stream: Stream.Type; VAR cx: ContextExpression.Str): BOOLEAN;
  169. PROCEDURE quotedString();
  170. VAR
  171. c: CHAR;
  172. s: STRING;
  173. BEGIN
  174. IF ~Stream.eof(stream) THEN
  175. c := Stream.getChar(stream);
  176. WHILE (c # doubleQuote) & ~Stream.eof(stream) DO
  177. IF c # doubleQuote THEN
  178. s := s + String.fromChar(c);
  179. END;
  180. c := Stream.getChar(stream);
  181. END;
  182. ELSE
  183. c := 0X;
  184. END;
  185. IF c # doubleQuote THEN
  186. Errors.raise("unexpected end of string");
  187. END;
  188. cx.handleStr(s);
  189. END;
  190. PROCEDURE hexString(firstChar: CHAR): BOOLEAN;
  191. BEGIN
  192. result <- FALSE;
  193. s <- String.fromChar(firstChar);
  194. WHILE ~Stream.eof(stream) & isHexDigit(Stream.peekChar(stream)) DO
  195. s := s + String.fromChar(Stream.getChar(stream));
  196. END;
  197. IF ~Stream.eof(stream) & (Stream.getChar(stream) = "X") THEN
  198. cx.handleStr(String.fromChar(CHR(String.parseHex(s))));
  199. result := TRUE;
  200. END;
  201. RETURN result;
  202. END;
  203. BEGIN
  204. result <- FALSE;
  205. IF ~Stream.eof(stream) THEN
  206. c <- Stream.getChar(stream);
  207. IF c = doubleQuote THEN
  208. quotedString();
  209. result := TRUE;
  210. ELSIF isDigit(c) THEN
  211. result := hexString(c);
  212. END
  213. END
  214. RETURN result
  215. END string;
  216. PROCEDURE ident*(VAR stream: Stream.Type; context: ContextHierarchy.Node; reservedWords: ARRAY OF STRING): BOOLEAN;
  217. VAR
  218. result: BOOLEAN;
  219. c: CHAR;
  220. s: STRING;
  221. BEGIN
  222. IF ~Stream.eof(stream) THEN
  223. c := Stream.getChar(stream);
  224. IF isLetter(c) THEN
  225. WHILE ~Stream.eof(stream) & (isLetter(c) OR isDigit(c)) DO (* OR c = "_" *)
  226. s := s + String.fromChar(c);
  227. c := Stream.getChar(stream);
  228. END;
  229. IF isLetter(c) OR isDigit(c) THEN
  230. s := s + String.fromChar(c);
  231. ELSE
  232. Stream.next(stream, -1);
  233. END;
  234. IF reservedWords.indexOf(s) = -1 THEN
  235. (*IF jsReservedWords.indexOf(s) # -1 THEN
  236. s := s + "$";
  237. END;*)
  238. context.handleIdent(s);
  239. result := TRUE;
  240. END
  241. END
  242. END
  243. RETURN result
  244. END ident;
  245. PROCEDURE skipComment(VAR stream: Stream.Type; context: ContextHierarchy.Node): BOOLEAN;
  246. VAR
  247. result: BOOLEAN;
  248. BEGIN
  249. IF Stream.peekStr(stream, commentBegin) THEN
  250. Stream.next(stream, LEN(commentBegin));
  251. WHILE ~Stream.peekStr(stream, commentEnd) DO
  252. IF ~skipComment(stream, context) THEN
  253. Stream.next(stream, 1);
  254. IF Stream.eof(stream) THEN
  255. Errors.raise("comment was not closed");
  256. END
  257. END
  258. END;
  259. Stream.next(stream, LEN(commentEnd));
  260. result := TRUE;
  261. END
  262. RETURN result
  263. END skipComment;
  264. PROCEDURE readSpaces(c: CHAR): BOOLEAN;
  265. RETURN (c = " ")
  266. OR (c = 8X)
  267. OR (c = 9X)
  268. OR (c = 0AX)
  269. OR (c = 0DX)
  270. END readSpaces;
  271. PROCEDURE skipSpaces*(VAR stream: Stream.Type; context: ContextHierarchy.Node);
  272. BEGIN
  273. WHILE Stream.read(stream, readSpaces)
  274. & skipComment(stream, context) DO
  275. END;
  276. END;
  277. PROCEDURE Literal.Literal(s: STRING)
  278. | s(s);
  279. END;
  280. PROCEDURE literal*(l: Literal; VAR stream: Stream.Type; context: ContextHierarchy.Node): BOOLEAN;
  281. VAR
  282. result: BOOLEAN;
  283. BEGIN
  284. IF Stream.peekStr(stream, l.s) THEN
  285. Stream.next(stream, LEN(l.s));
  286. IF ~isLetter(l.s[LEN(l.s) - 1])
  287. OR Stream.eof(stream)
  288. OR (~isLetter(Stream.peekChar(stream)) & ~isDigit(Stream.peekChar(stream)))
  289. THEN
  290. context.handleLiteral(l.s);
  291. result := TRUE;
  292. END;
  293. END;
  294. RETURN result
  295. END;
  296. END Lexer.