fork(5) download
  1. import java.io.*;
  2.  
  3. // Компилятор языка "О"
  4. public class Main{
  5.  
  6. static void Init() {
  7. Text.Reset();
  8. if( !Text.Ok )
  9. Error.Message(Text.Message);
  10. Scan.Init();
  11. Gen.Init();
  12. }
  13.  
  14. static void Done() {
  15. Text.Close();
  16. }
  17.  
  18. public static void main(String[] args) {
  19. System.out.println("\nКомпилятор языка О");
  20. if( args.length == 0 )
  21. Location.Path = null;
  22. else
  23. Location.Path = args[0];
  24. Init(); // Инициализация
  25. Pars.Compile(); // Компиляция
  26. OVM.Run(); // Выполнение
  27. Done(); // Завершение
  28. }
  29.  
  30. }
  31.  
  32. // Текущая позиция в исходном тексте
  33. class Location {
  34. static int Line; // Номер строки
  35. static int Pos; // Номер символа в строке
  36. static int LexPos; // Позиция начала лексемы
  37. static String Path; // Путь к файлу
  38. }
  39.  
  40. // Обработка ошибок
  41. class Error {
  42.  
  43. static void Message(String Msg) {
  44. int ELine = Location.Line;
  45. while( Text.Ch != Text.chEOL && Text.Ch != Text.chEOT )
  46. Text.NextCh();
  47. if( Text.Ch == Text.chEOT ) System.out.println();
  48. for( int i = 1; i < Location.LexPos; i++ )
  49. System.out.print(' ');
  50. System.out.println("^");
  51. System.out.println(
  52. "(Строка " + ELine + ") Ошибка: " + Msg
  53. );
  54. System.out.println();
  55. System.out.print("Нажмите ВВОД");
  56. try{ while( System.in.read() != '\n' ); }
  57. catch (IOException e) {};
  58. System.exit(0);
  59. }
  60.  
  61. static void Expected(String Msg) {
  62. Message("Ожидается " + Msg);
  63. }
  64.  
  65. static void Warning(String Msg) {
  66. System.out.println();
  67. System.out.println("Предупреждение: " + Msg);
  68. }
  69.  
  70. }
  71.  
  72. // Генератор кода
  73. class Gen {
  74.  
  75. static int PC;
  76.  
  77. static void Init() {
  78. PC = 0;
  79. }
  80.  
  81. static void Cmd(int Cmd) {
  82. if( PC < OVM.MEMSIZE )
  83. OVM.M[PC++] = Cmd;
  84. else
  85. Error.Message("Недостаточно памяти для кода");
  86. }
  87.  
  88. static void Fixup(int A) {
  89. while( A > 0 ) {
  90. int temp = OVM.M[A-2];
  91. OVM.M[A-2] = PC;
  92. A = temp;
  93. }
  94. }
  95.  
  96. static void Abs() {
  97. Cmd(OVM.cmDup);
  98. Cmd(0);
  99. Cmd(PC+3);
  100. Cmd(OVM.cmIfGE);
  101. Cmd(OVM.cmNeg);
  102. }
  103.  
  104. static void Min() {
  105. Cmd(Integer.MAX_VALUE);
  106. Cmd(OVM.cmNeg);
  107. Cmd(1);
  108. Cmd(OVM.cmSub);
  109. }
  110.  
  111. static void Odd() {
  112. Cmd(2);
  113. Cmd(OVM.cmMod);
  114. Cmd(1);
  115. Cmd(0); // Адрес перехода вперед
  116. Cmd(OVM.cmIfNE);
  117. }
  118.  
  119. static void Const(int C) {
  120. Cmd(Math.abs(C));
  121. if ( C < 0 )
  122. Cmd(OVM.cmNeg);
  123. }
  124.  
  125. static void Comp(int Lex) {
  126. Cmd(0); // Адрес перехода вперед
  127. switch( Lex ) {
  128. case Scan.lexEQ : Cmd(OVM.cmIfNE); break;
  129. case Scan.lexNE : Cmd(OVM.cmIfEQ); break;
  130. case Scan.lexLE : Cmd(OVM.cmIfGT); break;
  131. case Scan.lexLT : Cmd(OVM.cmIfGE); break;
  132. case Scan.lexGE : Cmd(OVM.cmIfLT); break;
  133. case Scan.lexGT : Cmd(OVM.cmIfLE); break;
  134. }
  135. }
  136.  
  137. static void Addr(Obj X) {
  138. Cmd(X.Val); // В текущую ячейку адрес предыдущей + 2
  139. X.Val = PC+1; // Адрес+2 = PC+1
  140. }
  141.  
  142. static void AllocateVariables() {
  143. Obj VRef; // Ссылка на переменную в таблице имен
  144.  
  145. VRef = Table.FirstVar(); // Найти первую переменную
  146. while( VRef != null ) {
  147. if ( VRef.Val == 0 )
  148. Error.Warning(
  149. "Переменная " + VRef.Name + " не используется"
  150. );
  151. else if( PC < OVM.MEMSIZE ) {
  152. Fixup(VRef.Val); // Адресная привязка переменной
  153. PC++;
  154. }
  155. else
  156. Error.Message("Недостаточно памяти для переменных");
  157. VRef = Table.NextVar(); // Найти следующую переменную
  158. }
  159. }
  160.  
  161. }
  162.  
  163. // Виртуальная машина
  164. class OVM {
  165.  
  166. static final int MEMSIZE = 8*1024;
  167.  
  168. static final int
  169. cmStop = -1,
  170.  
  171. cmAdd = -2,
  172. cmSub = -3,
  173. cmMult = -4,
  174. cmDiv = -5,
  175. cmMod = -6,
  176. cmNeg = -7,
  177.  
  178. cmLoad = -8,
  179. cmSave = -9,
  180.  
  181. cmDup = -10,
  182. cmDrop = -11,
  183. cmSwap = -12,
  184. cmOver = -13,
  185.  
  186. cmGOTO = -14,
  187. cmIfEQ = -15,
  188. cmIfNE = -16,
  189. cmIfLE = -17,
  190. cmIfLT = -18,
  191. cmIfGE = -19,
  192. cmIfGT = -20,
  193.  
  194. cmIn = -21,
  195. cmOut = -22,
  196. cmOutLn = -23;
  197.  
  198. static int M[] = new int[MEMSIZE];
  199.  
  200. static void readln() {
  201. try { while( System.in.read() != '\n' ); }
  202. catch (IOException e) {};
  203. }
  204.  
  205. private static StreamTokenizer input =
  206.  
  207. static int ReadInt() {
  208. try{ input.nextToken(); } catch (IOException e) {};
  209. return (int)input.nval;
  210. }
  211.  
  212. static void Run() {
  213. int PC = 0;
  214. int SP = MEMSIZE;
  215. int Cmd;
  216. int Buf;
  217.  
  218. loop: for (;;)
  219. if ( (Cmd = M[PC++]) >= 0 )
  220. M[--SP] = Cmd;
  221. else
  222. switch( Cmd ) {
  223. case cmAdd:
  224. SP++; M[SP] += M[SP-1];
  225. break;
  226. case cmSub:
  227. SP++; M[SP] -= M[SP-1];
  228. break;
  229. case cmMult:
  230. SP++; M[SP] *= M[SP-1];
  231. break;
  232. case cmDiv:
  233. SP++; M[SP] /= M[SP-1];
  234. break;
  235. case cmMod:
  236. SP++; M[SP] %= M[SP-1];
  237. break;
  238. case cmNeg:
  239. M[SP] = -M[SP];
  240. break;
  241. case cmLoad:
  242. M[SP] = M[M[SP]];
  243. break;
  244. case cmSave:
  245. M[M[SP+1]] = M[SP];
  246. SP += 2;
  247. break;
  248. case cmDup:
  249. SP--; M[SP] = M[SP+1];
  250. break;
  251. case cmDrop:
  252. SP++;
  253. break;
  254. case cmSwap:
  255. Buf = M[SP]; M[SP] = M[SP+1]; M[SP+1] = Buf;
  256. break;
  257. case cmOver:
  258. SP--; M[SP] = M[SP+2];
  259. break;
  260. case cmGOTO:
  261. PC = M[SP++];
  262. break;
  263. case cmIfEQ:
  264. if ( M[SP+2] == M[SP+1] )
  265. PC = M[SP];
  266. SP += 3;
  267. break;
  268. case cmIfNE:
  269. if ( M[SP+2] != M[SP+1] )
  270. PC = M[SP];
  271. SP += 3;
  272. break;
  273. case cmIfLE:
  274. if ( M[SP+2] <= M[SP+1] )
  275. PC = M[SP];
  276. SP += 3;
  277. break;
  278. case cmIfLT:
  279. if ( M[SP+2] < M[SP+1] )
  280. PC = M[SP];
  281. SP += 3;
  282. break;
  283. case cmIfGE:
  284. if ( M[SP+2] >= M[SP+1] )
  285. PC = M[SP];
  286. SP += 3;
  287. break;
  288. case cmIfGT:
  289. if ( M[SP+2] > M[SP+1] )
  290. PC = M[SP];
  291. SP += 3;
  292. break;
  293. case cmIn:
  294. System.out.print('?');
  295. M[--SP] = ReadInt();
  296. break;
  297. case cmOut:
  298. int w = M[SP] - (new Integer(M[SP+1])).
  299. toString().length();
  300. for( int i = 1; i <= w; i++ )
  301. System.out.print(" ");
  302. System.out.print(M[SP+1]);
  303. SP += 2;
  304. break;
  305. case cmOutLn:
  306. System.out.println();
  307. break;
  308. case cmStop:
  309. break loop;
  310. default:
  311. System.out.println("Недопустимый код операции");
  312. break loop;
  313. }
  314. System.out.println();
  315. if( SP < MEMSIZE )
  316. System.out.println("Код возврата " + M[SP]);
  317. }
  318.  
  319. }
  320.  
  321. // Распознаватель
  322. class Pars {
  323.  
  324. static final int
  325. spABS = 1,
  326. spMAX = 2,
  327. spMIN = 3,
  328. spDEC = 4,
  329. spODD = 5,
  330. spHALT = 6,
  331. spINC = 7,
  332. spInOpen = 8,
  333. spInInt = 9,
  334. spOutInt = 10,
  335. spOutLn = 11;
  336.  
  337. static void Check(int L, String M) {
  338. if( Scan.Lex != L )
  339. Error.Expected(M);
  340. else
  341. Scan.NextLex();
  342. }
  343.  
  344. // ["+" | "-"] (Число | Имя)
  345. static int ConstExpr() {
  346. int v = 0;
  347. Obj X;
  348. int Op;
  349.  
  350. Op = Scan.lexPlus;
  351. if( Scan.Lex == Scan.lexPlus ||
  352. Scan.Lex == Scan.lexMinus )
  353. {
  354. Op = Scan.Lex;
  355. Scan.NextLex();
  356. }
  357. if( Scan.Lex == Scan.lexNum ) {
  358. v = Scan.Num;
  359. Scan.NextLex();
  360. }
  361. else if( Scan.Lex == Scan.lexName ) {
  362. X = Table.Find(Scan.Name);
  363. if( X.Cat == Table.catGuard )
  364. Error.Message(
  365. "Нельзя определять константу через себя"
  366. );
  367. else if( X.Cat != Table.catConst )
  368. Error.Expected( "имя константы" );
  369. else {
  370. v = X.Val;
  371. Scan.NextLex();
  372. }
  373. }
  374. else
  375. Error.Expected( "константное выражение" );
  376. if( Op == Scan.lexMinus )
  377. return -v;
  378. return v;
  379. }
  380.  
  381. // Имя "=" КонстВыраж
  382. static void ConstDecl() {
  383. Obj ConstRef; // Ссылка на имя в таблице
  384.  
  385. ConstRef = Table.NewName(Scan.Name, Table.catGuard);
  386. Scan.NextLex();
  387. Check(Scan.lexEQ, "\"=\"");
  388. ConstRef.Val = ConstExpr();
  389. ConstRef.Typ = Table.typInt; //Констант других типов нет
  390. ConstRef.Cat = Table.catConst;
  391. }
  392.  
  393. static void ParseType() {
  394. Obj TypeRef;
  395. if( Scan.Lex != Scan.lexName )
  396. Error.Expected("имя");
  397. else {
  398. TypeRef = Table.Find(Scan.Name);
  399. if( TypeRef.Cat != Table.catType )
  400. Error.Expected("имя типа");
  401. else if( TypeRef.Typ != Table.typInt )
  402. Error.Expected("целый тип");
  403. Scan.NextLex();
  404. }
  405. }
  406.  
  407. // Имя {"," Имя} ":" Тип
  408. static void VarDecl() {
  409. Obj NameRef;
  410.  
  411. if( Scan.Lex != Scan.lexName )
  412. Error.Expected("имя");
  413. else {
  414. NameRef = Table.NewName(Scan.Name, Table.catVar);
  415. NameRef.Typ = Table.typInt;
  416. Scan.NextLex();
  417. }
  418. while( Scan.Lex == Scan.lexComma ) {
  419. Scan.NextLex();
  420. if( Scan.Lex != Scan.lexName )
  421. Error.Expected("имя");
  422. else {
  423. NameRef = Table.NewName(Scan.Name, Table.catVar );
  424. NameRef.Typ = Table.typInt;
  425. Scan.NextLex();
  426. }
  427. }
  428. Check(Scan.lexColon, "\":\"");
  429. ParseType();
  430. }
  431.  
  432. // { CONST {ОбъявлКонст ";"} | VAR {ОбъявлПерем ";"} }
  433. static void DeclSeq() {
  434. while( Scan.Lex == Scan.lexCONST ||
  435. Scan.Lex == Scan.lexVAR )
  436. {
  437. if( Scan.Lex == Scan.lexCONST ) {
  438. Scan.NextLex();
  439. while( Scan.Lex == Scan.lexName ) {
  440. ConstDecl(); //Объявление константы
  441. Check(Scan.lexSemi, "\";\"");
  442. }
  443. }
  444. else {
  445. Scan.NextLex(); // VAR
  446. while( Scan.Lex == Scan.lexName ) {
  447. VarDecl(); //Объявление переменных
  448. Check(Scan.lexSemi, "\";\"");
  449. }
  450. }
  451. }
  452. }
  453.  
  454. static void IntExpression() {
  455. if( Expression() != Table.typInt )
  456. Error.Expected("выражение целого типа");
  457. }
  458.  
  459. static int StFunc(int F) {
  460. switch( F ) {
  461. case spABS:
  462. IntExpression();
  463. Gen.Abs();
  464. return Table.typInt;
  465. case spMAX:
  466. ParseType();
  467. Gen.Cmd(Integer.MAX_VALUE);
  468. return Table.typInt;
  469. case spMIN:
  470. ParseType();
  471. Gen.Min();
  472. return Table.typInt;
  473. case spODD:
  474. IntExpression();
  475. Gen.Odd();
  476. return Table.typBool;
  477. }
  478. return Table.typNone; // Чтоб не было предупреждений
  479. }
  480.  
  481. static int Factor() {
  482. Obj X;
  483. int T = 0; // Чтоб не было предупреждений
  484.  
  485. if( Scan.Lex == Scan.lexName ) {
  486. if( (X = Table.Find(Scan.Name)).Cat == Table.catVar ) {
  487. Gen.Addr(X); //Адрес переменной
  488. Gen.Cmd(OVM.cmLoad);
  489. Scan.NextLex();
  490. return X.Typ;
  491. }
  492. else if( X.Cat == Table.catConst ) {
  493. Gen.Const(X.Val);
  494. Scan.NextLex();
  495. return X.Typ;
  496. }
  497. else if( X.Cat == Table.catStProc &&
  498. X.Typ != Table.typNone )
  499. {
  500. Scan.NextLex();
  501. Check(Scan.lexLPar, "\"(\"");
  502. T = StFunc(X.Val);
  503. Check(Scan.lexRPar, "\")\"");
  504. }
  505. else
  506. Error.Expected(
  507. "переменная, константа или процедура-функции"
  508. );
  509. }
  510. else if( Scan.Lex == Scan.lexNum ) {
  511. Gen.Const(Scan.Num);
  512. Scan.NextLex();
  513. return Table.typInt;
  514. }
  515. else if( Scan.Lex == Scan.lexLPar ) {
  516. Scan.NextLex();
  517. T = Expression();
  518. Check(Scan.lexRPar, "\")\"");
  519. }
  520. else
  521. Error.Expected("имя, число или \"(\"");
  522. return T;
  523. }
  524.  
  525. static int Term() {
  526. int Op;
  527. int T = Factor();
  528. if( Scan.Lex == Scan.lexMult || Scan.Lex == Scan.lexDIV
  529. || Scan.Lex == Scan.lexMOD )
  530. {
  531. if( T != Table.typInt )
  532. Error.Message(
  533. "Несоответствие операции типу операнда"
  534. );
  535. do {
  536. Op = Scan.Lex;
  537. Scan.NextLex();
  538. if( (T = Factor()) != Table.typInt )
  539. Error.Expected("выражение целого типа");
  540. switch( Op ) {
  541. case Scan.lexMult: Gen.Cmd(OVM.cmMult); break;
  542. case Scan.lexDIV: Gen.Cmd(OVM.cmDiv); break;
  543. case Scan.lexMOD: Gen.Cmd(OVM.cmMod); break;
  544. }
  545. } while( Scan.Lex == Scan.lexMult ||
  546. Scan.Lex == Scan.lexDIV ||
  547. Scan.Lex == Scan.lexMOD );
  548. }
  549. return T;
  550. }
  551.  
  552. // ["+"|"-"] Слагаемое {ОперСлож Слагаемое}
  553. static int SimpleExpr() {
  554. int T;
  555. int Op;
  556.  
  557. if( Scan.Lex == Scan.lexPlus ||
  558. Scan.Lex == Scan.lexMinus )
  559. {
  560. Op = Scan.Lex;
  561. Scan.NextLex();
  562. if( (T = Term()) != Table.typInt )
  563. Error.Expected("выражение целого типа");
  564. if( Op == Scan.lexMinus )
  565. Gen.Cmd(OVM.cmNeg);
  566. }
  567. else
  568. T = Term();
  569. if( Scan.Lex == Scan.lexPlus ||
  570. Scan.Lex == Scan.lexMinus )
  571. {
  572. if( T != Table.typInt )
  573. Error.Message(
  574. "Несоответствие операции типу операнда"
  575. );
  576. do {
  577. Op = Scan.Lex;
  578. Scan.NextLex();
  579. if( (T = Term()) != Table.typInt )
  580. Error.Expected("выражение целого типа");
  581. switch(Op) {
  582. case Scan.lexPlus: Gen.Cmd(OVM.cmAdd); break;
  583. case Scan.lexMinus: Gen.Cmd(OVM.cmSub); break;
  584. }
  585. } while( Scan.Lex == Scan.lexPlus ||
  586. Scan.Lex == Scan.lexMinus );
  587. }
  588. return T;
  589. }
  590.  
  591. // ПростоеВыраж [Отношение ПростоеВыраж]
  592. static int Expression() {
  593. int Op;
  594.  
  595. int T = SimpleExpr();
  596. if( Scan.Lex == Scan.lexEQ || Scan.Lex == Scan.lexNE ||
  597. Scan.Lex == Scan.lexGT || Scan.Lex == Scan.lexGE ||
  598. Scan.Lex == Scan.lexLT || Scan.Lex == Scan.lexLE )
  599. {
  600. Op = Scan.Lex;
  601. if( T != Table.typInt )
  602. Error.Message(
  603. "Несоответствие операции типу операнда"
  604. );
  605. Scan.NextLex();
  606. if( (T = SimpleExpr()) != Table.typInt )
  607. Error.Expected("выражение целого типа");
  608. Gen.Comp(Op); //Генерация условного перехода
  609. T = Table.typBool;
  610. } //иначе тип равен типу первого простого выражения
  611. return T;
  612. }
  613.  
  614. // Переменная = Имя
  615. static void Variable() {
  616. Obj X;
  617.  
  618. if( Scan.Lex != Scan.lexName )
  619. Error.Expected("имя");
  620. else {
  621. if( (X = Table.Find(Scan.Name)).Cat != Table.catVar )
  622. Error.Expected("имя переменной");
  623. Gen.Addr(X);
  624. Scan.NextLex();
  625. }
  626. }
  627.  
  628. static void StProc(int P) {
  629. switch( P ) {
  630. case spDEC:
  631. Variable();
  632. Gen.Cmd(OVM.cmDup);
  633. Gen.Cmd(OVM.cmLoad);
  634. if( Scan.Lex == Scan.lexComma ) {
  635. Scan.NextLex();
  636. IntExpression();
  637. }
  638. else
  639. Gen.Cmd(1);
  640. Gen.Cmd(OVM.cmSub);
  641. Gen.Cmd(OVM.cmSave);
  642. return;
  643. case spINC:
  644. Variable();
  645. Gen.Cmd(OVM.cmDup);
  646. Gen.Cmd(OVM.cmLoad);
  647. if( Scan.Lex == Scan.lexComma ) {
  648. Scan.NextLex();
  649. IntExpression();
  650. }
  651. else
  652. Gen.Cmd(1);
  653. Gen.Cmd(OVM.cmAdd);
  654. Gen.Cmd(OVM.cmSave);
  655. return;
  656. case spInOpen:
  657. // Пусто ;
  658. return;
  659. case spInInt:
  660. Variable();
  661. Gen.Cmd(OVM.cmIn);
  662. Gen.Cmd(OVM.cmSave);
  663. return;
  664. case spOutInt:
  665. IntExpression();
  666. Check(Scan.lexComma , "\",\"");
  667. IntExpression();
  668. Gen.Cmd(OVM.cmOut);
  669. return;
  670. case spOutLn:
  671. Gen.Cmd(OVM.cmOutLn);
  672. return;
  673. case spHALT:
  674. Gen.Const(ConstExpr());
  675. Gen.Cmd(OVM.cmStop);
  676. return;
  677. }
  678. }
  679.  
  680. static void BoolExpression() {
  681. if( Expression() != Table.typBool )
  682. Error.Expected("логическое выражение");
  683. }
  684.  
  685. // Переменная "=" Выраж
  686. static void AssStatement() {
  687. Variable();
  688. if( Scan.Lex == Scan.lexAss ) {
  689. Scan.NextLex();
  690. IntExpression();
  691. Gen.Cmd(OVM.cmSave);
  692. }
  693. else
  694. Error.Expected("\":=\"");
  695. }
  696.  
  697. // Имя ["(" // Выраж | Переменная ")"]
  698. static void CallStatement(int sp) {
  699. Check(Scan.lexName, "имя процедуры");
  700. if( Scan.Lex == Scan.lexLPar ) {
  701. Scan.NextLex();
  702. StProc(sp);
  703. Check( Scan.lexRPar, "\")\"" );
  704. }
  705. else if( sp == spOutLn || sp == spInOpen )
  706. StProc(sp);
  707. else
  708. Error.Expected("\"(\"");
  709. }
  710.  
  711. static void IfStatement() {
  712. int CondPC;
  713. int LastGOTO;
  714.  
  715. Check(Scan.lexIF, "IF");
  716. LastGOTO = 0; //Предыдущего перехода нет
  717. BoolExpression();
  718. CondPC = Gen.PC; //Запомн. положение усл. перехода
  719. Check(Scan.lexTHEN, "THEN");
  720. StatSeq();
  721. while( Scan.Lex == Scan.lexELSIF ) {
  722. Gen.Cmd(LastGOTO); //Фиктивный адрес, указывающий
  723. Gen.Cmd(OVM.cmGOTO); //на место предыдущего перехода
  724. LastGOTO = Gen.PC; //Запомнить место GOTO
  725. Scan.NextLex();
  726. Gen.Fixup(CondPC); //Зафикс. адрес условного перехода
  727. BoolExpression();
  728. CondPC = Gen.PC; //Запомн. положение усл. перехода
  729. Check(Scan.lexTHEN, "THEN");
  730. StatSeq();
  731. }
  732. if( Scan.Lex == Scan.lexELSE ) {
  733. Gen.Cmd(LastGOTO); //Фиктивный адрес, указывающий
  734. Gen.Cmd(OVM.cmGOTO); //на место предыдущего перехода
  735. LastGOTO = Gen.PC; //Запомнить место последнего GOTO
  736. Scan.NextLex();
  737. Gen.Fixup(CondPC); //Зафикс. адрес условного перехода
  738. StatSeq();
  739. }
  740. else
  741. Gen.Fixup(CondPC); //Если ELSE отсутствует
  742. Check( Scan.lexEND, "END" );
  743. Gen.Fixup(LastGOTO); //Направить сюда все GOTO
  744. }
  745.  
  746. static void WhileStatement() {
  747. int WhilePC = Gen.PC;
  748. Check(Scan.lexWHILE, "WHILE");
  749. BoolExpression();
  750. int CondPC = Gen.PC;
  751. Check(Scan.lexDO, "DO");
  752. StatSeq();
  753. Check(Scan.lexEND, "END");
  754. Gen.Cmd(WhilePC);
  755. Gen.Cmd(OVM.cmGOTO);
  756. Gen.Fixup(CondPC);
  757. }
  758.  
  759. static void Statement() {
  760. Obj X;
  761.  
  762. if( Scan.Lex == Scan.lexName ) {
  763. if( (X=Table.Find(Scan.Name)).Cat == Table.catModule )
  764. {
  765. Scan.NextLex();
  766. Check(Scan.lexDot, "\".\"");
  767. if( Scan.Lex == Scan.lexName &&
  768. X.Name.length() + Scan.Name.length() <=
  769. Scan.NAMELEN
  770. )
  771. X = Table.Find( X.Name + "." + Scan.Name);
  772. else
  773. Error.Expected("имя из модуля " + X.Name);
  774. }
  775. if( X.Cat == Table.catVar )
  776. AssStatement(); //Присваивание
  777. else if( X.Cat == Table.catStProc &&
  778. X.Typ == Table.typNone
  779. )
  780. CallStatement(X.Val); //Вызов процедуры
  781. else
  782. Error.Expected(
  783. "обозначение переменной или процедуры"
  784. );
  785. }
  786. else if( Scan.Lex == Scan.lexIF )
  787. IfStatement();
  788. else if( Scan.Lex == Scan.lexWHILE )
  789. WhileStatement();
  790. // иначе пустой оператор
  791. }
  792.  
  793. // Оператор {";" Оператор}
  794. static void StatSeq() {
  795. Statement(); //Оператор
  796. while( Scan.Lex == Scan.lexSemi ) {
  797. Scan.NextLex();
  798. Statement(); //Оператор
  799. }
  800. }
  801.  
  802. static void ImportName() {
  803. if( Scan.Lex == Scan.lexName ) {
  804. Table.NewName(Scan.Name, Table.catModule);
  805. if( Scan.Name.compareTo("In") == 0 ) {
  806. Table.Enter("In.Open",
  807. Table.catStProc, Table.typNone, spInOpen);
  808. Table.Enter("In.Int",
  809. Table.catStProc, Table.typNone, spInInt);
  810. }
  811. else if( Scan.Name.compareTo("Out") == 0 ) {
  812. Table.Enter("Out.Int",
  813. Table.catStProc, Table.typNone, spOutInt);
  814. Table.Enter("Out.Ln",
  815. Table.catStProc, Table.typNone, spOutLn);
  816. }
  817. else
  818. Error.Message("Неизвестный модуль");
  819. Scan.NextLex();
  820. }
  821. else
  822. Error.Expected("имя импортируемого модуля");
  823. }
  824.  
  825. // IMPORT Имя { "," Имя } ";"
  826. static void Import() {
  827. Check(Scan.lexIMPORT, "IMPORT");
  828. ImportName(); //Обработка имени импортируемого модуля
  829. while( Scan.Lex == Scan.lexComma ) {
  830. Scan.NextLex();
  831. ImportName(); //Обработка имени импортируемого модуля
  832. }
  833. Check(Scan.lexSemi, "\";\"");
  834. }
  835.  
  836. // MODULE Имя ";" [Импорт] ПослОбъявл [BEGIN ПослОператоров]
  837. // END Имя "."
  838. static void Module() {
  839. Obj ModRef; //Ссылка на имя модуля в таблице
  840.  
  841. Check(Scan.lexMODULE, "MODULE");
  842. if( Scan.Lex != Scan.lexName )
  843. Error.Expected("имя модуля");
  844. //Имя модуля - в таблицу имен
  845. ModRef = Table.NewName(Scan.Name, Table.catModule);
  846. Scan.NextLex();
  847. Check(Scan.lexSemi, "\";\"");
  848. if( Scan.Lex == Scan.lexIMPORT )
  849. Import();
  850. DeclSeq();
  851. if( Scan.Lex == Scan.lexBEGIN ) {
  852. Scan.NextLex();
  853. StatSeq();
  854. }
  855. Check(Scan.lexEND, "END");
  856.  
  857. //Сравнение имени модуля и имени после END
  858. if( Scan.Lex != Scan.lexName )
  859. Error.Expected("имя модуля");
  860. else if( Scan.Name.compareTo(ModRef.Name) != 0 )
  861. Error.Expected(
  862. "имя модуля \"" + ModRef.Name + "\""
  863. );
  864. else
  865. Scan.NextLex();
  866. if( Scan.Lex != Scan.lexDot )
  867. Error.Expected("\".\"");
  868. Gen.Cmd(0); // Код возврата
  869. Gen.Cmd(OVM.cmStop); // Команда останова
  870. Gen.AllocateVariables(); // Размещение переменных
  871. }
  872.  
  873. static void Compile() {
  874. Table.Init();
  875. Table.OpenScope(); //Блок стандартных имен
  876. Table.Enter("ABS",
  877. Table.catStProc, Table.typInt, spABS);
  878. Table.Enter("MAX",
  879. Table.catStProc, Table.typInt, spMAX);
  880. Table.Enter("MIN",
  881. Table.catStProc, Table.typInt, spMIN);
  882. Table.Enter("DEC",
  883. Table.catStProc, Table.typNone, spDEC);
  884. Table.Enter("ODD",
  885. Table.catStProc, Table.typBool, spODD);
  886. Table.Enter("HALT",
  887. Table.catStProc, Table.typNone, spHALT);
  888. Table.Enter("INC",
  889. Table.catStProc, Table.typNone, spINC);
  890. Table.Enter("INTEGER",
  891. Table.catType, Table.typInt, 0);
  892. Table.OpenScope(); //Блок модуля
  893. Module();
  894. Table.CloseScope(); //Блок модуля
  895. Table.CloseScope(); //Блок стандартных имен
  896. System.out.println("\nКомпиляция завершена");
  897. }
  898.  
  899. }
  900.  
  901. // Лексический анализатор
  902. class Scan {
  903.  
  904. static int NAMELEN = 31; // Наибольшая длина имени
  905.  
  906. final static int
  907. lexNone = 0,
  908. lexName = 1, lexNum = 2,
  909. lexMODULE = 3, lexIMPORT = 4,
  910. lexBEGIN = 5, lexEND = 6,
  911. lexCONST = 7, lexVAR = 8,
  912. lexWHILE = 9, lexDO = 10,
  913. lexIF = 11, lexTHEN = 12,
  914. lexELSIF = 13, lexELSE = 14,
  915. lexMult = 15, lexDIV = 16, lexMOD = 17,
  916. lexPlus = 18, lexMinus = 19,
  917. lexEQ = 20, lexNE = 21,
  918. lexLT = 22, lexLE = 23,
  919. lexGT = 24, lexGE = 25,
  920. lexDot = 26, lexComma = 27, lexColon = 28,
  921. lexSemi = 29, lexAss = 30,
  922. lexLPar = 31, lexRPar = 32,
  923. lexEOT = 33;
  924.  
  925. // Текущая лексема
  926. static int Lex;
  927. // Строковое значение имени
  928. private static StringBuffer Buf =
  929. new StringBuffer(NAMELEN);
  930. static String Name;
  931.  
  932. // Значение числовых литералов
  933. static int Num;
  934.  
  935. private static int KWNUM = 34;
  936. private static int nkw = 0;
  937.  
  938. static private class Item {
  939. String Word;
  940. int Lex;
  941. }
  942.  
  943. private static Item[] KWTable = new Item[KWNUM];
  944.  
  945. private static void EnterKW(String Name, int Lex) {
  946. (KWTable[nkw] = new Item()).Word = new String(Name); // !!
  947. KWTable[nkw++].Lex = Lex;
  948. }
  949.  
  950. private static int TestKW() {
  951. for( int i = nkw - 1; i >= 0; i-- )
  952. if( KWTable[i].Word.compareTo(Name) == 0 )
  953. return KWTable[i].Lex;
  954. return lexName;
  955. }
  956.  
  957. private static void Ident() {
  958. int i = 0;
  959. Buf.setLength(0);
  960. do {
  961. if ( i++ < NAMELEN )
  962. Buf.append((char)Text.Ch);
  963. else
  964. Error.Message("Слишком длинное имя");
  965. Text.NextCh();
  966. } while( Character.isLetterOrDigit((char)Text.Ch) );
  967. Name = Buf.toString();
  968. Lex = TestKW(); // Проверка на ключевое слово
  969. }
  970.  
  971. private static void Number() {
  972. Lex = lexNum;
  973. Num = 0;
  974. do {
  975. int d = Text.Ch - '0';
  976. if( (Integer.MAX_VALUE - d)/10 >= Num )
  977. Num = 10*Num + d;
  978. else
  979. Error.Message("Слишком большое число");
  980. Text.NextCh();
  981. } while( Character.isDigit((char)Text.Ch) );
  982. }
  983.  
  984. private static void Comment() {
  985. Text.NextCh();
  986. do {
  987. while( Text.Ch != '*' && Text.Ch != Text.chEOT )
  988. if( Text.Ch == '(' ) {
  989. Text.NextCh();
  990. if( Text.Ch == '*' )
  991. Comment();
  992. }
  993. else
  994. Text.NextCh();
  995. if ( Text.Ch == '*' )
  996. Text.NextCh();
  997. } while( Text.Ch != ')' && Text.Ch != Text.chEOT );
  998. if ( Text.Ch == ')' )
  999. Text.NextCh();
  1000. else {
  1001. Location.LexPos = Location.Pos;
  1002. Error.Message("Не закончен комментарий");
  1003. }
  1004. }
  1005.  
  1006. /*
  1007. private static void Comment() {
  1008.   int Level = 1;
  1009.   Text.NextCh();
  1010.   do
  1011.   if( Text.Ch == '*' ) {
  1012.   Text.NextCh();
  1013.   if( Text.Ch == ')' )
  1014.   { Level--; Text.NextCh(); }
  1015.   }
  1016.   else if( Text.Ch == '(' ) {
  1017.   Text.NextCh();
  1018.   if( Text.Ch == '*' )
  1019.   { Level++; Text.NextCh(); }
  1020.   }
  1021.   else //if ( Text.Ch <> chEOT )
  1022.   Text.NextCh();
  1023.   while( Level != 0 && Text.Ch != Text.chEOT );
  1024.   if( Level != 0 ) {
  1025.   Location.LexPos = Location.Pos;
  1026.   Error.Message("Не закончен комментарий");
  1027.   }
  1028. }
  1029. */
  1030.  
  1031. static void NextLex() {
  1032. while(
  1033. Text.Ch == Text.chSPACE ||
  1034. Text.Ch == Text.chTAB ||
  1035. Text.Ch == Text.chEOL
  1036. )
  1037. Text.NextCh();
  1038. Location.LexPos = Location.Pos;
  1039. if( Character.isLetter((char)Text.Ch) )
  1040. Ident();
  1041. else if( Character.isDigit((char)Text.Ch) )
  1042. Number();
  1043. else
  1044. switch( Text.Ch ) {
  1045. case ';':
  1046. Text.NextCh(); Lex = lexSemi;
  1047. break;
  1048. case ':':
  1049. Text.NextCh();
  1050. if( Text.Ch == '=' )
  1051. { Text.NextCh(); Lex = lexAss; }
  1052. else
  1053. Lex = lexColon;
  1054. break;
  1055. case '.':
  1056. Text.NextCh(); Lex = lexDot;
  1057. break;
  1058. case ',':
  1059. Text.NextCh(); Lex = lexComma;
  1060. break;
  1061. case '=':
  1062. Text.NextCh(); Lex = lexEQ;
  1063. break;
  1064. case '#':
  1065. Text.NextCh(); Lex = lexNE;
  1066. break;
  1067. case '<':
  1068. Text.NextCh();
  1069. if( Text.Ch == '=' )
  1070. { Text.NextCh(); Lex = lexLE; }
  1071. else
  1072. Lex = lexLT;
  1073. break;
  1074. case '>':
  1075. Text.NextCh();
  1076. if ( Text.Ch == '=' )
  1077. { Text.NextCh(); Lex = lexGE; }
  1078. else
  1079. Lex = lexGT;
  1080. break;
  1081. case '(':
  1082. Text.NextCh();
  1083. if( Text.Ch == '*' )
  1084. { Comment(); NextLex(); }
  1085. else
  1086. Lex = lexLPar;
  1087. break;
  1088. case ')':
  1089. Text.NextCh(); Lex = lexRPar;
  1090. break;
  1091. case '+':
  1092. Text.NextCh(); Lex = lexPlus;
  1093. break;
  1094. case '-':
  1095. Text.NextCh(); Lex = lexMinus;
  1096. break;
  1097. case '*':
  1098. Text.NextCh(); Lex = lexMult;
  1099. break;
  1100. case Text.chEOT:
  1101. Lex = lexEOT;
  1102. break;
  1103. default:
  1104. Error.Message("Недопустимый символ");
  1105. }
  1106. }
  1107.  
  1108. static void Init() {
  1109. EnterKW("ARRAY", lexNone);
  1110. EnterKW("BY", lexNone);
  1111. EnterKW("BEGIN", lexBEGIN);
  1112. EnterKW("CASE", lexNone);
  1113. EnterKW("CONST", lexCONST);
  1114. EnterKW("DIV", lexDIV);
  1115. EnterKW("DO", lexDO);
  1116. EnterKW("ELSE", lexELSE);
  1117. EnterKW("ELSIF", lexELSIF);
  1118. EnterKW("END", lexEND);
  1119. EnterKW("EXIT", lexNone);
  1120. EnterKW("FOR", lexNone);
  1121. EnterKW("IF", lexIF);
  1122. EnterKW("IMPORT", lexIMPORT);
  1123. EnterKW("IN", lexNone);
  1124. EnterKW("IS", lexNone);
  1125. EnterKW("LOOP", lexNone);
  1126. EnterKW("MOD", lexMOD);
  1127. EnterKW("MODULE", lexMODULE);
  1128. EnterKW("NIL", lexNone);
  1129. EnterKW("OF", lexNone);
  1130. EnterKW("OR", lexNone);
  1131. EnterKW("POINTER", lexNone);
  1132. EnterKW("PROCEDURE", lexNone);
  1133. EnterKW("RECORD", lexNone);
  1134. EnterKW("REPEAT", lexNone);
  1135. EnterKW("RETURN", lexNone);
  1136. EnterKW("THEN", lexTHEN);
  1137. EnterKW("TO", lexNone);
  1138. EnterKW("TYPE", lexNone);
  1139. EnterKW("UNTIL", lexNone);
  1140. EnterKW("VAR", lexVAR);
  1141. EnterKW("WHILE", lexWHILE);
  1142. EnterKW("WITH", lexNone);
  1143.  
  1144. NextLex();
  1145. }
  1146.  
  1147. }
  1148.  
  1149. // Элемент таблицы имен
  1150. class Obj { // Тип записи таблицы имен
  1151. String Name; // Ключ поиска
  1152. int Cat; // Категория имени
  1153. int Typ; // Тип
  1154. int Val; // Значение
  1155. Obj Prev; // Указатель на пред. имя
  1156. }
  1157.  
  1158. // Таблица имен
  1159. class Table {
  1160.  
  1161. // Категории имён
  1162. static final int
  1163. catConst = 1, catVar = 2,
  1164. catType = 3, catStProc = 4,
  1165. catModule = 5, catGuard = 6;
  1166.  
  1167. // Типы
  1168. static final int
  1169. typNone = 0, typInt = 1, typBool = 2;
  1170.  
  1171. private static Obj Top; //Указатель на вершину списка
  1172. private static Obj Bottom; //Указатель на конец списка
  1173. private static Obj CurrObj;
  1174.  
  1175. // Инициализация таблицы
  1176. static void Init() {
  1177. Top = null;
  1178. }
  1179.  
  1180. // Добавление элемента
  1181. static void Enter(String N, int C, int T, int V) {
  1182. Obj P = new Obj();
  1183. P.Name = new String(N);
  1184. P.Cat = C;
  1185. P.Typ = T;
  1186. P.Val = V;
  1187. P.Prev = Top;
  1188. Top = P;
  1189. }
  1190.  
  1191. static void OpenScope() {
  1192. Enter("", catGuard, typNone, 0);
  1193. if ( Top.Prev == null )
  1194. Bottom = Top;
  1195. }
  1196.  
  1197. static void CloseScope() {
  1198. while( Top.Cat != catGuard ){
  1199. Top = Top.Prev;
  1200. }
  1201. Top = Top.Prev;
  1202. }
  1203.  
  1204. static Obj NewName(String Name, int Cat) {
  1205. Obj obj = Top;
  1206. while(
  1207. obj.Cat != catGuard &&
  1208. obj.Name.compareTo(Name) != 0
  1209. )
  1210. obj = obj.Prev;
  1211. if ( obj.Cat == catGuard ) {
  1212. obj = new Obj();
  1213. obj.Name = new String(Name);
  1214. obj.Cat = Cat;
  1215. obj.Val = 0;
  1216. obj.Prev = Top;
  1217. Top = obj;
  1218. }
  1219. else
  1220. Error.Message("Повторное объявление имени");
  1221. return obj;
  1222. }
  1223.  
  1224. static Obj Find(String Name) {
  1225. Obj obj;
  1226.  
  1227. Bottom.Name = new String(Name);
  1228. for( obj=Top; obj.Name.compareTo(Name)!=0; obj=obj.Prev );
  1229. if( obj == Bottom )
  1230. Error.Message("Необъявленное имя");
  1231. return obj;
  1232. }
  1233.  
  1234. static Obj FirstVar() {
  1235. CurrObj = Top;
  1236. return NextVar();
  1237. }
  1238.  
  1239. static Obj NextVar() {
  1240. Obj VRef;
  1241.  
  1242. while( CurrObj != Bottom && CurrObj.Cat != catVar )
  1243. CurrObj = CurrObj.Prev;
  1244. if( CurrObj == Bottom )
  1245. return null;
  1246. else {
  1247. VRef = CurrObj;
  1248. CurrObj = CurrObj.Prev;
  1249. return VRef;
  1250. }
  1251. }
  1252.  
  1253. }
  1254.  
  1255. // Драйвер исходного текста
  1256. class Text {
  1257.  
  1258. static final int TABSIZE = 3;
  1259. static final char chSPACE = ' '; // Пробел
  1260. static final char chTAB = '\t'; // Табуляция
  1261. static final char chEOL = '\n'; // Конец строки
  1262. static final char chEOT = '\0'; // Конец текста
  1263.  
  1264. static boolean Ok = false;
  1265. static String Message = "Файл не открыт";
  1266. static int Ch = chEOT;
  1267.  
  1268. private static InputStream f;
  1269.  
  1270. static void NextCh() {
  1271. try {
  1272. if( (Ch = f.read()) == -1 )
  1273. Ch = chEOT;
  1274. else if( Ch == '\n' ) {
  1275. System.out.println();
  1276. Location.Line++; Location.Pos = 0; Ch = chEOL;
  1277. }
  1278. else if( Ch == '\r' )
  1279. NextCh();
  1280. else if( Ch != '\t' ) {
  1281. System.out.write(Ch); Location.Pos++;
  1282. }
  1283. else
  1284. do
  1285. System.out.print(' ');
  1286. while( ++Location.Pos % TABSIZE != 0 );
  1287. } catch (IOException e) {};
  1288. }
  1289.  
  1290. static void Reset() {
  1291. f = System.in;
  1292. Ok = true; Message = "Ok";
  1293. Location.Pos = 0; Location.Line = 1;
  1294. NextCh();
  1295. }
  1296.  
  1297. static void Close() {
  1298. try {
  1299. f.close();
  1300. } catch (IOException e) {};
  1301. }
  1302.  
  1303. }
  1304.  
Success #stdin #stdout 0.08s 2184192KB
stdin
MODULE Primes;
(* Простые числа от 2 до n *)

IMPORT In, Out;

VAR
   n, c, i, d : INTEGER;

BEGIN
   In.Open;
   In.Int(n);
   Out.Int(n, 0);
   Out.Ln;
   c := 0; (* Счетчик простых *)
   i := 2;
   WHILE i <= n DO
      (* Делим на 2, ... пока не разделится *)
         d := 2;
         WHILE i MOD d # 0 DO 
            INC(d) 
         END;
      IF d = i THEN (* i - простое *)
         INC(c);
         Out.Int(d, 8) 
      END;
      INC(i);
   END;
   Out.Ln;
   Out.Int(c,0);

END Primes. 
1000
stdout
Компилятор языка О
MODULE Primes;
(* Простые числа от 2 до n *)

IMPORT In, Out;

VAR
   n, c, i, d : INTEGER;

BEGIN
   In.Open;
   In.Int(n);
   Out.Int(n, 0);
   Out.Ln;
   c := 0; (* Счетчик простых *)
   i := 2;
   WHILE i <= n DO
      (* Делим на 2, ... пока не разделится *)
         d := 2;
         WHILE i MOD d # 0 DO 
            INC(d) 
         END;
      IF d = i THEN (* i - простое *)
         INC(c);
         Out.Int(d, 8) 
      END;
      INC(i);
   END;
   Out.Ln;
   Out.Int(c,0);

END Primes. 
Компиляция завершена
?1000
       2       3       5       7      11      13      17      19      23      29      31      37      41      43      47      53      59      61      67      71      73      79      83      89      97     101     103     107     109     113     127     131     137     139     149     151     157     163     167     173     179     181     191     193     197     199     211     223     227     229     233     239     241     251     257     263     269     271     277     281     283     293     307     311     313     317     331     337     347     349     353     359     367     373     379     383     389     397     401     409     419     421     431     433     439     443     449     457     461     463     467     479     487     491     499     503     509     521     523     541     547     557     563     569     571     577     587     593     599     601     607     613     617     619     631     641     643     647     653     659     661     673     677     683     691     701     709     719     727     733     739     743     751     757     761     769     773     787     797     809     811     821     823     827     829     839     853     857     859     863     877     881     883     887     907     911     919     929     937     941     947     953     967     971     977     983     991     997
168
Код возврата 0