ORS.Mod.txt 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. MODULE ORS; (* NW 19.9.93 / 20.3.2017 Scanner in Oberon-07*)
  2. IMPORT SYSTEM, Texts, Oberon;
  3. (* Oberon Scanner does lexical analysis. Input is Oberon-Text, output is
  4. sequence of symbols, i.e identifiers, numbers, strings, and special symbols.
  5. Recognises all Oberon keywords and skips comments. The keywords are
  6. recorded in a table.
  7. Get(sym) delivers next symbol from input text with Reader R.
  8. Mark(msg) records error and delivers error message with Writer W.
  9. If Get delivers ident, then the identifier (a string) is in variable id, if int or char
  10. in ival, if real in rval, and if string in str (and slen) *)
  11. CONST IdLen* = 32;
  12. NKW = 34; (*nof keywords*)
  13. maxExp = 38; stringBufSize = 256;
  14. (*lexical symbols*)
  15. null = 0; times* = 1; rdiv* = 2; div* = 3; mod* = 4;
  16. and* = 5; plus* = 6; minus* = 7; or* = 8; eql* = 9;
  17. neq* = 10; lss* = 11; leq* = 12; gtr* = 13; geq* = 14;
  18. in* = 15; is* = 16; arrow* = 17; period* = 18;
  19. char* = 20; int* = 21; real* = 22; false* = 23; true* = 24;
  20. nil* = 25; string* = 26; not* = 27; lparen* = 28; lbrak* = 29;
  21. lbrace* = 30; ident* = 31;
  22. if* = 32; while* = 34; repeat* = 35; case* = 36; for* = 37;
  23. comma* = 40; colon* = 41; becomes* = 42; upto* = 43; rparen* = 44;
  24. rbrak* = 45; rbrace* = 46; then* = 47; of* = 48; do* = 49;
  25. to* = 50; by* = 51; semicolon* = 52; end* = 53; bar* = 54;
  26. else* = 55; elsif* = 56; until* = 57; return* = 58;
  27. array* = 60; record* = 61; pointer* = 62; const* = 63; type* = 64;
  28. var* = 65; procedure* = 66; begin* = 67; import* = 68; module* = 69; eot = 70;
  29. TYPE Ident* = ARRAY IdLen OF CHAR;
  30. VAR ival*, slen*: LONGINT; (*results of Get*)
  31. rval*: REAL;
  32. id*: Ident; (*for identifiers*)
  33. str*: ARRAY stringBufSize OF CHAR;
  34. errcnt*: INTEGER;
  35. ch: CHAR; (*last character read*)
  36. errpos: LONGINT;
  37. R: Texts.Reader;
  38. W: Texts.Writer;
  39. k: INTEGER;
  40. KWX: ARRAY 10 OF INTEGER;
  41. keyTab: ARRAY NKW OF
  42. RECORD sym: INTEGER; id: ARRAY 12 OF CHAR END;
  43. PROCEDURE CopyId*(VAR ident: Ident);
  44. BEGIN ident := id
  45. END CopyId;
  46. PROCEDURE Pos*(): LONGINT;
  47. BEGIN RETURN Texts.Pos(R) - 1
  48. END Pos;
  49. PROCEDURE Mark*(msg: ARRAY OF CHAR);
  50. VAR p: LONGINT;
  51. BEGIN p := Pos();
  52. IF (p > errpos) & (errcnt < 25) THEN
  53. Texts.WriteLn(W); Texts.WriteString(W, " pos "); Texts.WriteInt(W, p, 1); Texts.Write(W, " ");
  54. Texts.WriteString(W, msg); Texts.Append(Oberon.Log, W.buf)
  55. END ;
  56. INC(errcnt); errpos := p + 4
  57. END Mark;
  58. PROCEDURE Identifier(VAR sym: INTEGER);
  59. VAR i, k: INTEGER;
  60. BEGIN i := 0;
  61. REPEAT
  62. IF i < IdLen-1 THEN id[i] := ch; INC(i) END ;
  63. Texts.Read(R, ch)
  64. UNTIL (ch < "0") OR (ch > "9") & (ch < "A") OR (ch > "Z") & (ch < "a") OR (ch > "z");
  65. id[i] := 0X;
  66. IF i < 10 THEN k := KWX[i-1]; (*search for keyword*)
  67. WHILE (id # keyTab[k].id) & (k < KWX[i]) DO INC(k) END ;
  68. IF k < KWX[i] THEN sym := keyTab[k].sym ELSE sym := ident END
  69. ELSE sym := ident
  70. END
  71. END Identifier;
  72. PROCEDURE String;
  73. VAR i: INTEGER;
  74. BEGIN i := 0; Texts.Read(R, ch);
  75. WHILE ~R.eot & (ch # 22X) DO
  76. IF ch >= " " THEN
  77. IF i < stringBufSize-1 THEN str[i] := ch; INC(i) ELSE Mark("string too long") END ;
  78. END ;
  79. Texts.Read(R, ch)
  80. END ;
  81. str[i] := 0X; INC(i); Texts.Read(R, ch); slen := i
  82. END String;
  83. PROCEDURE HexString;
  84. VAR i, m, n: INTEGER;
  85. BEGIN i := 0; Texts.Read(R, ch);
  86. WHILE ~R.eot & (ch # "$") DO
  87. WHILE ~R.eot & (ch <= " ") DO Texts.Read(R, ch) END ; (*skip*)
  88. IF ("0" <= ch) & (ch <= "9") THEN m := ORD(ch) - 30H
  89. ELSIF ("A" <= ch) & (ch <= "F") THEN m := ORD(ch) - 37H
  90. ELSE m := 0; Mark("hexdig expected")
  91. END ;
  92. Texts.Read(R, ch);
  93. IF ("0" <= ch) & (ch <= "9") THEN n := ORD(ch) - 30H
  94. ELSIF ("A" <= ch) & (ch <= "F") THEN n := ORD(ch) - 37H
  95. ELSE n := 0; Mark("hexdig expected")
  96. END ;
  97. IF i < stringBufSize THEN str[i] := CHR(m*10H + n); INC(i) ELSE Mark("string too long") END ;
  98. Texts.Read(R, ch)
  99. END ;
  100. Texts.Read(R, ch); slen := i (*no 0X appended!*)
  101. END HexString;
  102. PROCEDURE Ten(e: LONGINT): REAL;
  103. VAR x, t: REAL;
  104. BEGIN x := 1.0; t := 10.0;
  105. WHILE e > 0 DO
  106. IF ODD(e) THEN x := t * x END ;
  107. t := t * t; e := e DIV 2
  108. END ;
  109. RETURN x
  110. END Ten;
  111. PROCEDURE Number(VAR sym: INTEGER);
  112. CONST max = 2147483647 (*2^31 - 1*);
  113. VAR i, k, e, n, s, h: LONGINT; x: REAL;
  114. d: ARRAY 16 OF INTEGER;
  115. negE: BOOLEAN;
  116. BEGIN ival := 0; i := 0; n := 0; k := 0;
  117. REPEAT
  118. IF n < 16 THEN d[n] := ORD(ch)-30H; INC(n) ELSE Mark("too many digits"); n := 0 END ;
  119. Texts.Read(R, ch)
  120. UNTIL (ch < "0") OR (ch > "9") & (ch < "A") OR (ch > "F");
  121. IF (ch = "H") OR (ch = "R") OR (ch = "X") THEN (*hex*)
  122. REPEAT h := d[i];
  123. IF h >= 10 THEN h := h-7 END ;
  124. k := k*10H + h; INC(i) (*no overflow check*)
  125. UNTIL i = n;
  126. IF ch = "X" THEN sym := char;
  127. IF k < 100H THEN ival := k ELSE Mark("illegal value"); ival := 0 END
  128. ELSIF ch = "R" THEN sym := real; rval := SYSTEM.VAL(REAL, k)
  129. ELSE sym := int; ival := k
  130. END ;
  131. Texts.Read(R, ch)
  132. ELSIF ch = "." THEN
  133. Texts.Read(R, ch);
  134. IF ch = "." THEN (*double dot*) ch := 7FX; (*decimal integer*)
  135. REPEAT
  136. IF d[i] < 10 THEN
  137. IF k <= (max-d[i]) DIV 10 THEN k := k *10 + d[i] ELSE Mark("too large"); k := 0 END
  138. ELSE Mark("bad integer")
  139. END ;
  140. INC(i)
  141. UNTIL i = n;
  142. sym := int; ival := k
  143. ELSE (*real number*) x := 0.0; e := 0;
  144. REPEAT (*integer part*) x := x * 10.0 + FLT(d[i]); INC(i) UNTIL i = n;
  145. WHILE (ch >= "0") & (ch <= "9") DO (*fraction*)
  146. x := x * 10.0 + FLT(ORD(ch) - 30H); DEC(e); Texts.Read(R, ch)
  147. END ;
  148. IF (ch = "E") OR (ch = "D") THEN (*scale factor*)
  149. Texts.Read(R, ch); s := 0;
  150. IF ch = "-" THEN negE := TRUE; Texts.Read(R, ch)
  151. ELSE negE := FALSE;
  152. IF ch = "+" THEN Texts.Read(R, ch) END
  153. END ;
  154. IF (ch >= "0") & (ch <= "9") THEN
  155. REPEAT s := s*10 + ORD(ch)-30H; Texts.Read(R, ch)
  156. UNTIL (ch < "0") OR (ch >"9");
  157. IF negE THEN e := e-s ELSE e := e+s END
  158. ELSE Mark("digit?")
  159. END
  160. END ;
  161. IF e < 0 THEN
  162. IF e >= -maxExp THEN x := x / Ten(-e) ELSE x := 0.0 END
  163. ELSIF e > 0 THEN
  164. IF e <= maxExp THEN x := Ten(e) * x ELSE x := 0.0; Mark("too large") END
  165. END ;
  166. sym := real; rval := x
  167. END
  168. ELSE (*decimal integer*)
  169. REPEAT
  170. IF d[i] < 10 THEN
  171. IF k <= (max-d[i]) DIV 10 THEN k := k*10 + d[i] ELSE Mark("too large"); k := 0 END
  172. ELSE Mark("bad integer")
  173. END ;
  174. INC(i)
  175. UNTIL i = n;
  176. sym := int; ival := k
  177. END
  178. END Number;
  179. PROCEDURE comment;
  180. BEGIN Texts.Read(R, ch);
  181. REPEAT
  182. WHILE ~R.eot & (ch # "*") DO
  183. IF ch = "(" THEN Texts.Read(R, ch);
  184. IF ch = "*" THEN comment END
  185. ELSE Texts.Read(R, ch)
  186. END
  187. END ;
  188. WHILE ch = "*" DO Texts.Read(R, ch) END
  189. UNTIL (ch = ")") OR R.eot;
  190. IF ~R.eot THEN Texts.Read(R, ch) ELSE Mark("unterminated comment") END
  191. END comment;
  192. PROCEDURE Get*(VAR sym: INTEGER);
  193. BEGIN
  194. REPEAT
  195. WHILE ~R.eot & (ch <= " ") DO Texts.Read(R, ch) END;
  196. IF R.eot THEN sym := eot
  197. ELSIF ch < "A" THEN
  198. IF ch < "0" THEN
  199. IF ch = 22X THEN String; sym := string
  200. ELSIF ch = "#" THEN Texts.Read(R, ch); sym := neq
  201. ELSIF ch = "$" THEN HexString; sym := string
  202. ELSIF ch = "&" THEN Texts.Read(R, ch); sym := and
  203. ELSIF ch = "(" THEN Texts.Read(R, ch);
  204. IF ch = "*" THEN sym := null; comment ELSE sym := lparen END
  205. ELSIF ch = ")" THEN Texts.Read(R, ch); sym := rparen
  206. ELSIF ch = "*" THEN Texts.Read(R, ch); sym := times
  207. ELSIF ch = "+" THEN Texts.Read(R, ch); sym := plus
  208. ELSIF ch = "," THEN Texts.Read(R, ch); sym := comma
  209. ELSIF ch = "-" THEN Texts.Read(R, ch); sym := minus
  210. ELSIF ch = "." THEN Texts.Read(R, ch);
  211. IF ch = "." THEN Texts.Read(R, ch); sym := upto ELSE sym := period END
  212. ELSIF ch = "/" THEN Texts.Read(R, ch); sym := rdiv
  213. ELSE Texts.Read(R, ch); (* ! % ' *) sym := null
  214. END
  215. ELSIF ch < ":" THEN Number(sym)
  216. ELSIF ch = ":" THEN Texts.Read(R, ch);
  217. IF ch = "=" THEN Texts.Read(R, ch); sym := becomes ELSE sym := colon END
  218. ELSIF ch = ";" THEN Texts.Read(R, ch); sym := semicolon
  219. ELSIF ch = "<" THEN Texts.Read(R, ch);
  220. IF ch = "=" THEN Texts.Read(R, ch); sym := leq ELSE sym := lss END
  221. ELSIF ch = "=" THEN Texts.Read(R, ch); sym := eql
  222. ELSIF ch = ">" THEN Texts.Read(R, ch);
  223. IF ch = "=" THEN Texts.Read(R, ch); sym := geq ELSE sym := gtr END
  224. ELSE (* ? @ *) Texts.Read(R, ch); sym := null
  225. END
  226. ELSIF ch < "[" THEN Identifier(sym)
  227. ELSIF ch < "a" THEN
  228. IF ch = "[" THEN sym := lbrak
  229. ELSIF ch = "]" THEN sym := rbrak
  230. ELSIF ch = "^" THEN sym := arrow
  231. ELSE (* _ ` *) sym := null
  232. END ;
  233. Texts.Read(R, ch)
  234. ELSIF ch < "{" THEN Identifier(sym) ELSE
  235. IF ch = "{" THEN sym := lbrace
  236. ELSIF ch = "}" THEN sym := rbrace
  237. ELSIF ch = "|" THEN sym := bar
  238. ELSIF ch = "~" THEN sym := not
  239. ELSIF ch = 7FX THEN sym := upto
  240. ELSE sym := null
  241. END ;
  242. Texts.Read(R, ch)
  243. END
  244. UNTIL sym # null
  245. END Get;
  246. PROCEDURE Init*(T: Texts.Text; pos: LONGINT);
  247. BEGIN errpos := pos; errcnt := 0; Texts.OpenReader(R, T, pos); Texts.Read(R, ch)
  248. END Init;
  249. PROCEDURE EnterKW(sym: INTEGER; name: ARRAY OF CHAR);
  250. BEGIN keyTab[k].id := name; keyTab[k].sym := sym; INC(k)
  251. END EnterKW;
  252. BEGIN Texts.OpenWriter(W); k := 0; KWX[0] := 0; KWX[1] := 0;
  253. EnterKW(if, "IF");
  254. EnterKW(do, "DO");
  255. EnterKW(of, "OF");
  256. EnterKW(or, "OR");
  257. EnterKW(to, "TO");
  258. EnterKW(in, "IN");
  259. EnterKW(is, "IS");
  260. EnterKW(by, "BY");
  261. KWX[2] := k;
  262. EnterKW(end, "END");
  263. EnterKW(nil, "NIL");
  264. EnterKW(var, "VAR");
  265. EnterKW(div, "DIV");
  266. EnterKW(mod, "MOD");
  267. EnterKW(for, "FOR");
  268. KWX[3] := k;
  269. EnterKW(else, "ELSE");
  270. EnterKW(then, "THEN");
  271. EnterKW(true, "TRUE");
  272. EnterKW(type, "TYPE");
  273. EnterKW(case, "CASE");
  274. KWX[4] := k;
  275. EnterKW(elsif, "ELSIF");
  276. EnterKW(false, "FALSE");
  277. EnterKW(array, "ARRAY");
  278. EnterKW(begin, "BEGIN");
  279. EnterKW(const, "CONST");
  280. EnterKW(until, "UNTIL");
  281. EnterKW(while, "WHILE");
  282. KWX[5] := k;
  283. EnterKW(record, "RECORD");
  284. EnterKW(repeat, "REPEAT");
  285. EnterKW(return, "RETURN");
  286. EnterKW(import, "IMPORT");
  287. EnterKW(module, "MODULE");
  288. KWX[6] := k;
  289. EnterKW(pointer, "POINTER");
  290. KWX[7] := k; KWX[8] := k;
  291. EnterKW(procedure, "PROCEDURE");
  292. KWX[9] := k
  293. END ORS.