Parser.Mod 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. MODULE Parser;
  2. IMPORT Out, Files, S := Scanner, ST := SymTable, Gen := Generator;
  3. VAR sym: INTEGER;
  4. dc: INTEGER; (*Счётчик данных (data counter)*)
  5. dummy: ST.Object; (*Болванка, см. QualIdent*)
  6. PROCEDURE ^Expression(VAR x: Gen.Item);
  7. (*импорт = идент [":=" идент].*)
  8. PROCEDURE Import;
  9. VAR ident1, ident2: ARRAY 32 OF CHAR;
  10. BEGIN
  11. IF sym = S.ident THEN
  12. ident1 := S.id;
  13. S.Get(sym);
  14. IF sym = S.becomes THEN
  15. S.Get(sym);
  16. IF sym = S.ident THEN
  17. ident2 := S.id;
  18. S.Get(sym)
  19. ELSE
  20. S.Mark("Ожидается идентификатор")
  21. END
  22. ELSE
  23. ident2 := ident1
  24. END;
  25. ST.Import(ident1, ident2)
  26. ELSE
  27. S.Mark("Ожидается идентификатор")
  28. END
  29. END Import;
  30. (*СписокИмпорта = IMPORT импорт {"," импорт} ";".*)
  31. PROCEDURE ImportList;
  32. BEGIN
  33. IF sym = S.import THEN
  34. S.Get(sym);
  35. Import;
  36. WHILE sym = S.comma DO
  37. S.Get(sym);
  38. Import
  39. END;
  40. IF sym = S.semicolon THEN
  41. S.Get(sym)
  42. ELSE
  43. S.Mark("Ожидается точка с запятой")
  44. END
  45. END
  46. END ImportList;
  47. PROCEDURE Type(VAR tp: ST.Type);
  48. VAR o: ST.Object;
  49. BEGIN
  50. tp := ST.intType; (*Тип по умолчанию, используется в случае ошибки*)
  51. IF sym = S.ident THEN
  52. o := ST.ThisObj();
  53. S.Get(sym);
  54. IF o = NIL THEN
  55. S.Mark("Нет такого типа")
  56. ELSIF o.class # ST.Typ THEN
  57. S.Mark("Это не тип")
  58. ELSE
  59. tp := o.type
  60. END
  61. ELSE (*!TODO учесть ARRAY, RECORD и др.*)
  62. S.Mark("Ожидается тип")
  63. END
  64. END Type;
  65. (*Объявления = [CONST {ОбъявлениеКонстант ";"}]
  66. [TYPE {ОбъявлениеТипов ";"}]
  67. [VAR {ОбъявлениеПеременных ";"}]
  68. {ОбъявлениеПроцедуры ";"}.
  69. ОбъявлениеПеременных = Идентификаторы ":" Тип.
  70. Идентификаторы = Идентификатор {"," Идентификатор}.
  71. Тип = уточнИдент | ТипМассив | ТипЗапись | ТипУказатель | ПроцедурныйТип.
  72. Но в начале будет только VAR, поэтому используется упрощённый вариант:
  73. Объявления = [VAR {ОбъявлениеПеременных ";"}].
  74. ОбъявлениеПеременных = Идентификаторы ":" Тип.
  75. Идентификаторы = Идентификатор {"," Идентификатор}.
  76. Тип = Идентификатор.*)
  77. PROCEDURE Declarations(VAR varsize: INTEGER);
  78. VAR tp: ST.Type;
  79. i, n: INTEGER;
  80. o: ST.Object;
  81. names: ARRAY 30, 32 OF CHAR;
  82. BEGIN
  83. IF sym = S.var THEN (*1. Если считано слово VAR, то:*)
  84. S.Get(sym); (*Переходим к названию первой переменной*)
  85. WHILE sym = S.ident DO
  86. names[0] := S.id;
  87. S.Get(sym); (*Переходим к запятой или к двоеточию*)
  88. n := 1;
  89. WHILE sym = S.comma DO
  90. S.Get(sym); (*Переходим к названию следующей перменной*)
  91. IF sym = S.ident THEN
  92. IF n < LEN(names) THEN
  93. names[n] := S.id;
  94. INC(n)
  95. ELSE
  96. S.Mark("Слишком много переменных")
  97. END
  98. ELSE
  99. S.Mark("Ожидается идентификатор")
  100. END;
  101. S.Get(sym) (*Переходим к запятой или к двоеточию*)
  102. END;
  103. IF sym = S.colon THEN
  104. S.Get(sym);
  105. Type(tp);
  106. FOR i := 0 TO n - 1 DO
  107. o := ST.NewObj(names[i], ST.Var);
  108. o.type := tp;
  109. o.val := varsize;
  110. INC(varsize, 4);(*!TODO учитывать размер типа и выравнивание*)
  111. Out.String("Объявлена переменная "); Out.String(names[i]);
  112. Out.String(" типа "); ST.OutType(o.type);
  113. Out.String(" (адрес "); Out.Int(o.val, 0); Out.String(").");
  114. Out.Ln
  115. END;
  116. IF sym = S.semicolon THEN
  117. S.Get(sym)
  118. ELSE
  119. S.Mark("Ожидается точка с запятой")
  120. END
  121. ELSE
  122. S.Mark("Ожидается двоеточие")
  123. END
  124. END
  125. END
  126. END Declarations;
  127. (*УПРОЩЕНО: множитель = число | литера | идент | "(" выражение ")".*)
  128. PROCEDURE Factor(VAR x: Gen.Item);
  129. VAR o: ST.Object;
  130. BEGIN
  131. IF sym = S.int THEN
  132. x.mode := ST.Const;
  133. x.type := ST.intType;
  134. x.val := S.ival;
  135. Out.String("Прочитано число ");
  136. Out.Int(S.ival, 0); Out.Ln;
  137. S.Get(sym)
  138. ELSIF sym = S.char THEN
  139. x.mode := ST.Const;
  140. x.type := ST.charType;
  141. x.val := S.ival;
  142. Out.String("Прочитана литера ");
  143. Out.Char(CHR(S.ival)); Out.Ln;
  144. S.Get(sym)
  145. ELSIF sym = S.string THEN
  146. x.mode := ST.Const;
  147. x.type := ST.charType;
  148. x.val := ORD(S.sval[0]);
  149. IF S.slen = 1 THEN
  150. Out.String("Прочитана литера ");
  151. Out.Char(S.sval[0]); Out.Ln
  152. ELSE
  153. S.Mark("Допускается только CHAR")
  154. END;
  155. S.Get(sym)
  156. ELSIF sym = S.ident THEN
  157. o := ST.ThisObj();
  158. S.Get(sym);
  159. IF o = NIL THEN
  160. S.Mark("Идентификатор не объявлен")
  161. ELSE
  162. x.mode := o.class;
  163. x.type := o.type;
  164. x.val := o.val
  165. END
  166. ELSIF sym = S.lparen THEN
  167. S.Get(sym);
  168. Expression(x);
  169. IF sym = S.rparen THEN S.Get(sym)
  170. ELSE S.Mark("Ожидается )")
  171. END
  172. ELSE
  173. S.Mark("Ожидается число, идентификатор или (")
  174. END
  175. END Factor;
  176. (*слагаемое = множитель {ОперацияУмножения множитель}.*)
  177. PROCEDURE Term(VAR x: Gen.Item);
  178. VAR op: INTEGER;
  179. y: Gen.Item;
  180. BEGIN
  181. Factor(x);
  182. WHILE (sym = S.times) OR (sym = S.div) OR (sym = S.mod) DO
  183. op := sym;
  184. S.Get(sym);
  185. Factor(y);
  186. IF (x.type.form = ST.Int) & (y.type.form = ST.Int) THEN
  187. IF (x.mode = ST.Const) & (y.mode = ST.Const) THEN
  188. IF op = S.times THEN
  189. x.val := x.val * y.val (*!TODO проверить переполнение*)
  190. ELSE (*DIV OR MOD*)
  191. IF op = S.div THEN (*!TODO проверить деление на нуль*)
  192. x.val := x.val DIV y.val
  193. ELSE
  194. x.val := x.val MOD y.val
  195. END
  196. END
  197. ELSE
  198. IF op = S.times THEN
  199. Out.String("умножение")
  200. ELSIF op = S.div THEN
  201. Out.String("деление")
  202. ELSE
  203. Out.String("остаток от деления")
  204. END
  205. END
  206. ELSE
  207. S.Mark("Операция неприменима")
  208. END;
  209. Out.Ln
  210. END
  211. END Term;
  212. (*ПростоеВыражение = ["+"|"-"] слагаемое {ОператорСложения слагаемое}.*)
  213. PROCEDURE SimpleExpression(VAR x: Gen.Item);
  214. VAR minus: BOOLEAN;
  215. op: INTEGER;
  216. y: Gen.Item;
  217. BEGIN
  218. minus := FALSE;
  219. IF sym = S.plus THEN
  220. S.Get(sym)
  221. ELSIF sym = S.minus THEN
  222. minus := TRUE;
  223. S.Get(sym)
  224. END;
  225. Term(x);
  226. IF minus THEN
  227. IF x.type.form = ST.Int THEN
  228. IF x.mode = ST.Const THEN
  229. x.val := -x.val
  230. ELSE
  231. Out.String("Унарный минус"); Out.Ln
  232. END
  233. ELSE
  234. S.Mark("Операция унарного минуса неприменима")
  235. END
  236. END;
  237. WHILE (sym = S.plus) OR (sym = S.minus) DO
  238. op := sym;
  239. S.Get(sym);
  240. Term(y);
  241. IF (x.type.form = ST.Int) & (y.type.form = ST.Int) THEN
  242. IF (x.mode = ST.Const) & (y.mode = ST.Const) THEN
  243. IF op = S.plus THEN
  244. INC(x.val, y.val) (*!TODO проверить переполнение*)
  245. ELSE
  246. DEC(x.val, y.val) (*!TODO проверить переполнение*)
  247. END
  248. ELSE
  249. IF op = S.plus THEN
  250. Out.String("плюс")
  251. ELSE
  252. Out.String("минус")
  253. END
  254. END
  255. ELSE
  256. S.Mark("Операция неприменима")
  257. END;
  258. Out.Ln
  259. END
  260. END SimpleExpression;
  261. (*выражение = ПростоеВыражение [отношение ПростоеВыражение].*)
  262. PROCEDURE Expression(VAR x: Gen.Item);
  263. BEGIN
  264. SimpleExpression(x)
  265. END Expression;
  266. (*Присваивание = идент ":=" выражение.
  267. x - то, что слева от знака присваивания,
  268. y - то, что справа от знака присваивания.*)
  269. PROCEDURE Assignment(VAR x: Gen.Item);
  270. VAR y: Gen.Item;
  271. BEGIN
  272. S.Get(sym); (*пропускаем :=*)
  273. Expression(y);
  274. IF x.type = y.type THEN
  275. Out.String("Переменной по адресу ");
  276. Out.Int(x.val, 0);
  277. Out.String(" присвоено значение ");
  278. Out.Int(y.val, 0); Out.Char("."); Out.Ln
  279. ELSE
  280. S.Mark("Не совпадают типы")
  281. END
  282. END Assignment;
  283. (*уточнИдент = [идент "."] идент.
  284. Первый идент - это модуль. *)
  285. PROCEDURE QualIdent(VAR o: ST.Object);
  286. BEGIN
  287. o := ST.ThisObj();
  288. S.Get(sym);
  289. IF o = NIL THEN
  290. S.Mark("Нет такого объекта")
  291. ELSE (*Объект найден...*)
  292. IF (sym = S.period) & (o.class = ST.Mod) THEN (*...и это модуль*)
  293. S.Get(sym);
  294. o := ST.ThisObjInModule(o);
  295. S.Get(sym);
  296. IF o = NIL THEN S.Mark("В модуле нет такого объекта") END
  297. END
  298. END;
  299. IF o = NIL THEN o := dummy END
  300. END QualIdent;
  301. (*Designator - обозначение.
  302. Обозначение = уточнИдент {селектор}.
  303. селектор = "[" выражение "]" | ...
  304. Но здесь упрощено: Обозначение = уточнИдент.*)
  305. PROCEDURE Designator(VAR o: ST.Object);
  306. BEGIN
  307. QualIdent(o) (*!TODO обработать селекторы*)
  308. END Designator;
  309. PROCEDURE Parameter(par: ST.Object);
  310. VAR x: Gen.Item;
  311. BEGIN
  312. Expression(x);
  313. IF par # NIL THEN
  314. IF x.type.form # par.type.form THEN
  315. S.Mark("Несогласование типов")
  316. (*!TODO вывести типы формального и фактического параметров*)
  317. ELSIF (par.class = ST.Par) & (x.mode # ST.Var) THEN
  318. S.Mark("Требуется вар-параметр")
  319. ELSE
  320. Out.String("Параметр "); Out.Int(x.val, 0); Out.Char("."); Out.Ln
  321. END
  322. END
  323. END Parameter;
  324. (*ФактическиеПараметры = "(" [выражение {"," выражение}] ")".
  325. Предусловие: sym = S.lparen. Обрабатывает до ")" включительно.*)
  326. PROCEDURE ActualParameters(VAR x: Gen.Item);
  327. VAR y: Gen.Item;
  328. par: ST.Object;
  329. n: INTEGER; (*Фактическое количество параметров*)
  330. BEGIN
  331. S.Get(sym);(*Пропускаем "("*)
  332. n := 0;
  333. IF sym # S.rparen THEN
  334. par := x.type.dsc;
  335. Parameter(par);
  336. INC(n);
  337. WHILE sym = S.comma DO
  338. S.Get(sym); (*Пропускаем ","*)
  339. IF par # NIL THEN par := par.next END;
  340. Parameter(par);
  341. INC(n)
  342. END
  343. END;
  344. IF sym = S.rparen THEN S.Get(sym)
  345. ELSE S.Mark("Не закрыта скобка")
  346. END;
  347. (*Проверка совпадения количества параметров*)
  348. IF n > x.type.nofpar THEN
  349. S.Mark("Слишком много фактических параметров")
  350. ELSIF n < x.type.nofpar THEN
  351. S.Mark("Недостаточно фактических параметров")
  352. END
  353. END ActualParameters;
  354. (*Операторы = Оператор {";" Оператор}.
  355. Оператор = [Присваивание | ВызовПроцедуры | ОператорIf |
  356. ОператорCase | ОператорWhile | ОператорRepeat | ОператорFor].
  357. Statements/Операторы означает последовательность операторов.*)
  358. PROCEDURE Statements;
  359. VAR x: Gen.Item;
  360. o: ST.Object;
  361. BEGIN
  362. REPEAT
  363. WHILE sym = S.semicolon DO S.Get(sym) END;
  364. IF sym = S.ident THEN
  365. Designator(o);
  366. Gen.MakeItem(x, o);
  367. IF sym = S.eql THEN sym := S.becomes; S.Mark("Ожидается :=") END;
  368. IF sym = S.becomes THEN Assignment(x)
  369. ELSIF sym = S.lparen THEN (*Например: Out.Int(... *)
  370. IF x.type.form = ST.Proc THEN (*Это действительно процедура*)
  371. IF x.type.base.form # ST.NoTyp THEN (*Функциональная*)
  372. S.Mark("Не используется возвращаемое значение")
  373. ELSE
  374. ActualParameters(x); (*Обрабатывает до ")" включительно*)
  375. Gen.Call(x)
  376. END
  377. ELSE S.Mark("Это не процедура")
  378. END
  379. ELSIF x.type.form = ST.Proc THEN(*Вызов процедуры без параметров*)
  380. IF x.type.nofpar > 0 THEN S.Mark("Требуются параметры") END;
  381. IF x.type.base.form # ST.NoTyp THEN (*Функциональная*)
  382. S.Mark("Не используется возвращаемое значение")
  383. ELSE
  384. Gen.Call(x)
  385. END
  386. ELSE S.Mark("Инструкция неопознана")
  387. END
  388. END
  389. UNTIL sym # S.semicolon
  390. END Statements;
  391. (*Модуль = MODULE идент ";" [СписокИмпорта] Объявления
  392. [BEGIN Операторы] END идент ".".*)
  393. PROCEDURE Module;
  394. VAR name: ARRAY 32 OF CHAR;
  395. BEGIN
  396. IF sym = S.module THEN
  397. S.Get(sym);
  398. IF sym = S.ident THEN name := S.id; S.Get(sym)
  399. ELSE S.Mark("Ожидается идентификатор"); name[0] := 0X
  400. END;
  401. IF sym = S.semicolon THEN S.Get(sym)
  402. ELSE S.Mark("Ожидается точка с запятой")
  403. END;
  404. ImportList;
  405. dc := 80002000;
  406. Declarations(dc);
  407. IF sym = S.begin THEN S.Get(sym); Statements END;
  408. IF sym = S.end THEN
  409. S.Get(sym);
  410. IF sym = S.ident THEN
  411. IF name # S.id THEN S.Mark("Название модуля не совпадает") END;
  412. S.Get(sym)
  413. ELSE
  414. S.Mark("Ожидается название модуля")
  415. END;
  416. IF sym # S.period THEN S.Mark("Нет точки в конце модуля") END
  417. ELSE S.Mark("Ожидается END")
  418. END
  419. ELSE S.Mark("Ожидается модуль")
  420. END
  421. END Module;
  422. PROCEDURE Init;
  423. BEGIN
  424. ST.Init;
  425. NEW(dummy); dummy.class := ST.Var; dummy.type := ST.intType
  426. END Init;
  427. (*Разбирает лексемы, получаемые из модуля Scanner, в соответствии
  428. с синтаксисом языка Оберон. Возвращает TRUE в случае
  429. успешной компиляции. Вызывается из модуля Compiler.
  430. В будущем будет вызывать кодогенератор (из отдельного модуля). *)
  431. PROCEDURE Compile*(): BOOLEAN;
  432. BEGIN
  433. Init;
  434. Gen.WriteDummy; (*Сгенерировать исполнимый файл. Хардкод.*)
  435. S.Get(sym); (* олучить наперёд одну лексему*)
  436. Module; (*Запустить разбор синтаксической структуры МОДУЛЬ*)
  437. ST.Display;
  438. RETURN ~S.error
  439. END Compile;
  440. END Parser.