fork download
  1. <?php
  2.  
  3. /*
  4. PL/0 Compiler+Interpreter
  5. v1.0 Beta
  6. 2009-04-11 (last mod: 2009-04-11)
  7. */
  8.  
  9. // symbol table record structure
  10. class tablerec
  11. {
  12. public $name;
  13. public $kind;
  14. public $lvl;
  15. public $addr;
  16. public $val;
  17.  
  18. public function __construct($n, $k)
  19. {
  20. $this->name = $n;
  21. $this->kind = $k;
  22. }
  23.  
  24. public function __toString()
  25. {
  26. return "$this->name\t$this->kind\t$this->lvl\t$this->addr\t$this->val";
  27. }
  28. }
  29.  
  30. // p-code instruction structure
  31. class instr
  32. {
  33. public $i;
  34. public $l;
  35. public $a;
  36.  
  37. public function __construct($i, $l, $a)
  38. {
  39. $this->i = $i;
  40. $this->l = $l;
  41. $this->a = $a;
  42. }
  43.  
  44. public function __toString()
  45. {
  46. return "$this->i $this->l $this->a";
  47. }
  48. }
  49.  
  50. // globals
  51. $web = ($_SERVER["DOCUMENT_ROOT"] == "" ? false : true); // we have to know if the input comes from stdin or the web
  52. $data; // the input
  53. $ch; // current character read
  54. $line; // current line read
  55. $i = 0;
  56. $rwords = array("BEGIN", "CALL", "CASE", "CEND", "CONST", "DO", "DOWNTO", "ELSE", "END", "FOR", "IF", "ODD", "OF", "PROCEDURE", "REPEAT", "THEN", "TO", "UNTIL", "VAR", "WHILE", "WRITE", "WRITELN"); // reserved words
  57. $ops = array("+", "-", "*", "/", "(", ")", "=", ",", ".", "<>", "<", ">", "<=", ">=", ";", ":", ":="); // operators
  58. $ops_names = array("PLUS", "MINUS", "TIMES", "SLASH", "LPAREN", "RPAREN", "EQUAL", "COMMA", "PERIOD", "NE", "LT", "GT", "LTE", "GTE", "SEMICOLON", "COLON", "BECOMES"); // operator names
  59. $instr = array("LIT", "OPR", "LOD", "STO", "CAL", "INT", "JMP", "JPC"); // pcode instructions
  60. $st_types = array("CONSTANT", "VARIABLE", "PROCEDURE"); // symbol table types
  61. $sym; // current sym
  62. $id; // current IDENT
  63. $table; // symbol table
  64. $code; // program store
  65. $value; // current NUMBER value
  66. $codeinx = 0;
  67. $norw = 22; // number of reserved words
  68. $txmax = 100; // max number of IDENT in symbol table
  69. $nmax = 14; // max length of NUMBER
  70. $al = 10; // max length of IDENT
  71.  
  72. // BLOCK
  73. function block($tx, $lev)
  74. {
  75. global $sym, $codeinx, $table, $code;
  76.  
  77. $dx = 3;
  78. $tx0 = $tx;
  79. $codeinx0;
  80. $table[$tx]->addr = $codeinx;
  81. gen("JMP", 0, 0);
  82.  
  83. while ($sym == "CONST" || $sym == "VAR" || $sym == "PROCEDURE")
  84. {
  85. if ($sym == "CONST")
  86. {
  87. do
  88. {
  89. getsym();
  90. $tx = constdeclaration($tx, $lev, $dx);
  91. }
  92. while ($sym == "COMMA");
  93. if ($sym != "SEMICOLON")
  94. error(4);
  95. getsym();
  96. }
  97. if ($sym == "VAR")
  98. {
  99. do
  100. {
  101. getsym();
  102. $tx = vardeclaration($tx, $lev, $dx);
  103. }
  104. while ($sym == "COMMA");
  105. if ($sym != "SEMICOLON")
  106. error(4);
  107. getsym();
  108. }
  109. while ($sym == "PROCEDURE")
  110. {
  111. getsym();
  112. if ($sym != "IDENT")
  113. error(1);
  114. $tx = enter("PROCEDURE", $tx, $lev, $dx);
  115. getsym();
  116. if ($sym != "SEMICOLON")
  117. error(4);
  118. getsym();
  119. block($tx, $lev + 1);
  120. if ($sym != "SEMICOLON")
  121. error(4);
  122. getsym();
  123. }
  124. }
  125. $code[$table[$tx0]->addr]->a = $codeinx;
  126. $table[$tx0]->addr = $codeinx;
  127. $codeinx0 = $codeinx;
  128. gen("INT", 0, $dx);
  129. # print_st($tx);
  130. statement($tx, $lev);
  131. gen("OPR", 0, 0);
  132. listcode($codeinx0);
  133. }
  134.  
  135. // STATEMENT
  136. function statement($tx, $lev)
  137. {
  138. global $sym, $id, $table, $codeinx, $code, $value;
  139.  
  140. if ($sym == "IDENT")
  141. {
  142. $i = position($id, $tx);
  143. if ($i == 0)
  144. error(13);
  145. if ($table[$i]->kind != "VARIABLE")
  146. error(14);
  147. getsym();
  148. if ($sym != "BECOMES")
  149. error(6);
  150. getsym();
  151. expression($tx, $lev);
  152. gen("STO", $lev - $table[$i]->lvl, $table[$i]->addr);
  153. }
  154. else if ($sym == "CALL")
  155. {
  156. getsym();
  157. if ($sym != "IDENT")
  158. error(1);
  159. $i = position($id, $tx);
  160. if ($i == 0)
  161. error(13);
  162. if ($table[$i]->kind != "PROCEDURE")
  163. error(15);
  164. getsym();
  165. gen("CAL", $lev - $table[$i]->lvl, $table[$i]->addr);
  166. }
  167. else if ($sym == "BEGIN")
  168. {
  169. do
  170. {
  171. getsym();
  172. statement($tx, $lev);
  173. }
  174. while ($sym == "SEMICOLON");
  175. if ($sym != "END")
  176. error(7);
  177. getsym();
  178. }
  179. else if ($sym == "IF")
  180. {
  181. getsym();
  182. condition($tx, $lev);
  183. $cx1 = $codeinx;
  184. gen("JPC", 0, 0);
  185. if ($sym != "THEN")
  186. error(8);
  187. getsym();
  188. statement($tx, $lev);
  189. $code[$cx1]->a = $codeinx;
  190. /***** ADD CODE FOR ELSE HERE *****/
  191. }
  192. else if ($sym == "WHILE")
  193. {
  194. getsym();
  195. $cx1 = $codeinx;
  196. condition($tx, $lev);
  197. $cx2 = $codeinx;
  198. gen("JPC", 0, 0);
  199. if ($sym != "DO")
  200. error(9);
  201. getsym();
  202. statement($tx, $lev);
  203. gen("JMP", 0, $cx1);
  204. $code[$cx2]->a = $codeinx;
  205. }
  206. else if ($sym == "REPEAT")
  207. {
  208. /***** ADD CODE FOR REPEAT-UNTIL HERE *****/
  209. }
  210. else if ($sym == "WRITE")
  211. {
  212. /***** ADD CODE FOR WRITE HERE *****/
  213. }
  214. else if ($sym == "WRITELN")
  215. {
  216. /***** ADD CODE FOR WRITELN HERE *****/
  217. }
  218. else if ($sym == "FOR")
  219. {
  220. /***** ADD CODE FOR FOR-DO HERE *****/
  221. }
  222. else if ($sym == "CASE")
  223. {
  224. /***** ADD CODE FOR CASE-CEND HERE *****/
  225. }
  226. }
  227.  
  228. // CONDITION
  229. function condition($tx, $lev)
  230. {
  231. global $sym;
  232. $savesym;
  233.  
  234. if ($sym == "ODD")
  235. {
  236. getsym();
  237. expression($tx, $lev);
  238. gen("OPR", 0, 6);
  239. }
  240. else
  241. {
  242. expression($tx, $lev);
  243. if ($sym != "EQUAL" && $sym != "NE" && $sym != "LT" && $sym != "GT" && $sym != "LTE" && $sym != "GTE")
  244. error(10);
  245. $savesym = $sym;
  246. getsym();
  247. expression($tx, $lev);
  248. switch ($savesym)
  249. {
  250. case "EQUAL":
  251. gen("OPR", 0, 8);
  252. break;
  253. case "NE":
  254. gen("OPR", 0, 9);
  255. break;
  256. case "LT":
  257. gen("OPR", 0, 10);
  258. break;
  259. case "GT":
  260. gen("OPR", 0, 12);
  261. break;
  262. case "LTE":
  263. gen("OPR", 0, 13);
  264. break;
  265. case "GTE":
  266. gen("OPR", 0, 11);
  267. break;
  268. }
  269. }
  270. }
  271.  
  272. // EXPRESSION
  273. function expression($tx, $lev)
  274. {
  275. global $sym;
  276. $savesym;
  277.  
  278. if ($sym == "PLUS" || $sym == "MINUS")
  279. {
  280. $savesym = $sym;
  281. getsym();
  282. }
  283. term($tx, $lev);
  284. if ($savesym == "MINUS")
  285. gen("OPR", 0, 1);
  286. while ($sym == "PLUS" || $sym == "MINUS")
  287. {
  288. $savesym = $sym;
  289. getsym();
  290. term($tx, $lev);
  291. if ($savesym == "PLUS")
  292. gen("OPR", 0, 2);
  293. else
  294. gen("OPR", 0, 3);
  295. }
  296. }
  297.  
  298. // TERM
  299. function term($tx, $lev)
  300. {
  301. global $sym;
  302. $savesym;
  303.  
  304. factor($tx, $lev);
  305. while ($sym == "TIMES" || $sym == "SLASH")
  306. {
  307. $savesym = $sym;
  308. getsym();
  309. factor($tx, $lev);
  310. if ($savesym == "TIMES")
  311. gen("OPR", 0, 4);
  312. else
  313. gen("OPR", 0, 5);
  314. }
  315. }
  316.  
  317. // FACTOR
  318. function factor($tx, $lev)
  319. {
  320. global $sym, $id, $table, $value;
  321.  
  322. if ($sym == "IDENT")
  323. {
  324. $i = position($id, $tx);
  325. if ($i == 0)
  326. error(13);
  327. switch ($table[$i]->kind)
  328. {
  329. case "VARIABLE":
  330. gen("LOD", $lev - $table[$i]->lvl, $table[$i]->addr);
  331. break;
  332. case "CONSTANT":
  333. gen("LIT", 0, $table[$i]->val);
  334. break;
  335. case "PROCEDURE":
  336. error(14);
  337. break;
  338. }
  339. getsym();
  340. }
  341. else if ($sym == "NUMBER")
  342. {
  343. gen("LIT", 0, $value);
  344. getsym();
  345. }
  346. else if ($sym == "LPAREN")
  347. {
  348. getsym();
  349. expression($tx, $lev);
  350. if ($sym != "RPAREN")
  351. error(11);
  352. getsym();
  353. }
  354. else
  355. error(12);
  356. }
  357.  
  358. // determines the position of an identifier in the symbol table
  359. function position($id, $tx)
  360. {
  361. global $table;
  362.  
  363. // what we're looking for goes in table[0]
  364. $table[0]->name = $id;
  365. // search from the current tx on up
  366. for ($i = $tx; $i >= 0; $i--)
  367. {
  368. if ($table[$i]->name == $id)
  369. return $i;
  370. }
  371.  
  372. return 0;
  373. }
  374.  
  375. // enters an identifier in the symbol table
  376. function enter($kind, $tx, $lev, &$dx)
  377. {
  378. global $id, $table, $value;
  379.  
  380. // we should use txmax to keep symbol table at its max size
  381. $tx++;
  382. $table[$tx] = new tablerec($id, $kind);
  383. if ($kind == "CONSTANT")
  384. $table[$tx]->val = $value;
  385. else if ($kind == "VARIABLE")
  386. {
  387. $table[$tx]->lvl = $lev;
  388. $table[$tx]->addr = $dx;
  389. $dx++;
  390. }
  391. else if ($kind == "PROCEDURE")
  392. $table[$tx]->lvl = $lev;
  393.  
  394. return $tx;
  395. }
  396.  
  397. // prints the symbol table (for debugging)
  398. function print_st($tx)
  399. {
  400. global $table;
  401.  
  402. echo "\tNAME\tKIND\t\tLEVEL\tADDRESS\tVALUE\n";
  403. for ($i = 0; $i <= $tx; $i++)
  404. echo "$i\t" . $table[$i]->name . "\t" . $table[$i]->kind . "\t" . $table[$i]->lvl . "\t" . $table[$i]->addr . "\t" . $table[$i]->val . "\n";
  405. }
  406.  
  407. // lists the code for the block
  408. function listcode($codeinx0)
  409. {
  410. global $codeinx, $code, $web;
  411.  
  412. for ($i = $codeinx0; $i < $codeinx; $i++)
  413. echo "$i $code[$i]" . ($web ? "<br/>\n" : "\n");
  414. echo "\n";
  415. }
  416.  
  417. // generates a p-code instruction
  418. function gen($i, $l, $a)
  419. {
  420. global $codeinx, $code;
  421.  
  422. $code[$codeinx] = new instr($i, $l, $a);
  423. $codeinx++;
  424. }
  425.  
  426. // declares constants (and enters in symbol table)
  427. function constdeclaration($tx, $lev, &$dx)
  428. {
  429. global $sym;
  430.  
  431. if ($sym != "IDENT")
  432. error(1);
  433. getsym();
  434. if ($sym != "EQUAL")
  435. error(2);
  436. getsym();
  437. if ($sym != "NUMBER")
  438. error(3);
  439. getsym();
  440. $tx = enter("CONSTANT", $tx, $lev, $dx);
  441.  
  442. return $tx;
  443. }
  444.  
  445. // declares variables (and enters in symbol table)
  446. function vardeclaration($tx, $lev, &$dx)
  447. {
  448. global $sym;
  449.  
  450. if ($sym != "IDENT")
  451. error(1);
  452. getsym();
  453. $tx = enter("VARIABLE", $tx, $lev, $dx);
  454.  
  455. return $tx;
  456. }
  457.  
  458. // handles errors
  459. function error($i)
  460. {
  461. global $sym, $id;
  462.  
  463. switch ($i)
  464. {
  465. case 1:
  466. echo "Identifier expected";
  467. break;
  468. case 2:
  469. echo "EQUAL (=) expected";
  470. break;
  471. case 3:
  472. echo "NUMBER expected";
  473. break;
  474. case 4:
  475. echo "SEMICOLON (;) expected";
  476. break;
  477. case 5:
  478. echo "PERIOD (.) expected";
  479. break;
  480. case 6:
  481. echo "BECOMES (:=) expected";
  482. break;
  483. case 7:
  484. echo "END expected";
  485. break;
  486. case 8:
  487. echo "THEN expected";
  488. break;
  489. case 9:
  490. echo "DO expected";
  491. break;
  492. case 10:
  493. echo "Relational operator expected";
  494. break;
  495. case 11:
  496. echo "RPAREN (() expected";
  497. break;
  498. case 12:
  499. echo "An expression cannot begin with this symbol";
  500. break;
  501. case 13:
  502. echo "Undeclared identifier";
  503. break;
  504. case 14:
  505. echo "Assignment to CONSTANT or PROCEDURE not allowed";
  506. break;
  507. case 15:
  508. echo "CALL must be followed by a PROCEDURE";
  509. break;
  510. case 16:
  511. echo "UNTIL expected";
  512. break;
  513. case 17:
  514. echo "LPAREN (() expected";
  515. break;
  516. case 18:
  517. echo "TO or DOWNTO expected";
  518. break;
  519. case 19:
  520. echo "NUMBER or CONSTANT expected";
  521. break;
  522. case 20:
  523. echo "COLON (:) expected";
  524. break;
  525. case 21:
  526. echo "OF expected";
  527. break;
  528. case 22:
  529. echo "CEND expected";
  530. break;
  531. default:
  532. echo "Unknown error!";
  533. break;
  534. }
  535.  
  536. echo "; got $sym" . ($sym == "IDENT" ? " ($id)" : "") . "\n";
  537.  
  538. }
  539.  
  540. // GETSYM
  541. function getsym()
  542. {
  543. global $sym, $ch, $id, $rwords, $ops, $ops_names, $line, $value, $nmax, $al;
  544.  
  545. $sym = false;
  546. // skip whitespace
  547. while (!isset($ch) || $ch == "" || $ch == " " || $ch == "\r" || $ch == "\n")
  548. {
  549. if ($ch === false)
  550. return;
  551. getchar();
  552. }
  553.  
  554. // we either have an identifier or a reserved word
  555. if ($ch >= "A" && $ch <= "Z")
  556. {
  557. $tok = $ch;
  558. getchar();
  559. while (($ch >= "A" && $ch <= "Z") || ($ch >= "0" && $ch <= "9"))
  560. {
  561. if (strlen($tok) == $al)
  562. error();
  563.  
  564. $tok .= $ch;
  565. if ($line == "")
  566. {
  567. getchar();
  568. break;
  569. }
  570. getchar();
  571. }
  572.  
  573. // assume an identifier but search through reserved words
  574. $sym = "IDENT";
  575. // we could use norw here as sentinel, but why?
  576. foreach($rwords as $rword)
  577. {
  578. if ($tok == $rword)
  579. {
  580. $sym = $rword;
  581. break;
  582. }
  583. }
  584. if ($sym == "IDENT")
  585. $id = $tok;
  586. }
  587. // we have a number
  588. else if ($ch >= "0" && $ch <= "9")
  589. {
  590. $tok = $ch;
  591. getchar();
  592. while ($ch >= "0" && $ch <= "9")
  593. {
  594. if (strlen($tok) == $nmax)
  595. error();
  596.  
  597. $tok .= $ch;
  598. getchar();
  599. }
  600.  
  601. $sym = "NUMBER";
  602. $value = $tok;
  603. }
  604. // we have some other symbol
  605. else
  606. {
  607. // perhaps : or :=
  608. if ($ch == ":")
  609. {
  610. $tok = $ch;
  611. getchar();
  612. if ($ch == "=")
  613. {
  614. $tok .= $ch;
  615. getchar();
  616. }
  617. }
  618. // maybe <, <>, or <=
  619. else if ($ch == "<")
  620. {
  621. $tok = $ch;
  622. getchar();
  623. if ($ch == ">" || $ch == "=")
  624. {
  625. $tok .= $ch;
  626. getchar();
  627. }
  628. }
  629. // > or >=
  630. else if ($ch == ">")
  631. {
  632. $tok = $ch;
  633. getchar();
  634. if ($ch == "=")
  635. {
  636. $tok .= $ch;
  637. getchar();
  638. }
  639. }
  640. // some other single-character symbol
  641. else
  642. {
  643. $tok = $ch;
  644. getchar();
  645. }
  646.  
  647. // match the symbol and get its name
  648. for ($i = 0; $i < sizeof($ops); $i++)
  649. {
  650. if ($tok == $ops[$i])
  651. {
  652. $sym = $ops_names[$i];
  653. break;
  654. }
  655. }
  656. }
  657. }
  658.  
  659. // GETCHAR
  660. function getchar()
  661. {
  662. global $line, $ch;
  663.  
  664. // if we don't yet have a line, get one
  665. if ($line == "")
  666. {
  667. // if we're at the end of input, get out
  668. if (getline() === false)
  669. {
  670. $ch = false;
  671. return;
  672. }
  673. }
  674.  
  675. // get the current character and remainder of the line
  676. $ch = $line[0];
  677. $line = substr($line, 1);
  678. }
  679.  
  680. // GETLINE
  681. function getline()
  682. {
  683. global $line, $data, $i, $web;
  684.  
  685. // if we're at the end of input, get out
  686. if ($i == sizeof($data))
  687. return false;
  688.  
  689. // get the next line
  690. $line = $data[$i++];
  691. echo ($web ? (str_replace(" ", "&nbsp;", $line) . "<br/>\n") : "$line\n");
  692. }
  693.  
  694. function print_stack($s, $b, $t)
  695. {
  696. for ($i = $t; $i > 0; $i--)
  697. {
  698. $st = "$i: $s[$i]";
  699. if ($b == $i)
  700. $st .= "\tB";
  701. if ($t == $i)
  702. $st .= "\tT";
  703. echo "$st\n";
  704. }
  705. }
  706.  
  707. function base($l, $b, $s)
  708. {
  709. while ($l > 0)
  710. {
  711. $b = $s[$b];
  712. $l--;
  713. }
  714.  
  715. return $b;
  716. }
  717.  
  718. function interpret()
  719. {
  720. global $web, $code;
  721.  
  722. echo "Start PL/0" . ($web ? "<br/>\n" : "\n");
  723. $t = 0;
  724. $b = 1;
  725. $p = 0;
  726. $s[1] = 0;
  727. $s[2] = 0;
  728. $s[3] = 0;
  729.  
  730. while (true)
  731. {
  732. $i = $code[$p]->i;
  733. $l = $code[$p]->l;
  734. $a = $code[$p]->a;
  735. # echo "$p: $i $l $a\n";
  736. $p++;
  737.  
  738. switch ($i)
  739. {
  740. case "LIT":
  741. $t++;
  742. $s[$t] = $a;
  743. break;
  744. case "OPR":
  745. switch ($a)
  746. {
  747. case 0:
  748. $t = $b - 1;
  749. $p = $s[$t+3];
  750. $b = $s[$t+2];
  751. break;
  752. case 1:
  753. $s[$t] = $s[$t] * -1;
  754. break;
  755. case 2:
  756. $t--;
  757. $s[$t] = $s[$t] + $s[$t+1];
  758. break;
  759. case 3:
  760. $t--;
  761. $s[$t] = $s[$t] - $s[$t+1];
  762. break;
  763. case 4:
  764. $t--;
  765. $s[$t] = $s[$t] * $s[$t+1];
  766. break;
  767. case 5:
  768. $t--;
  769. $s[$t] = ($s[$t] - ($s[$t] % $s[$t+1])) / $s[$t+1];
  770. break;
  771. case 6:
  772. $s[$t] = ($s[$t] % 2 == 0 ? 0 : 1);
  773. break;
  774. case 8:
  775. $t--;
  776. $s[$t] = ($s[$t] == $s[$t+1] ? 1 : 0);
  777. break;
  778. case 9:
  779. $t--;
  780. $s[$t] = ($s[$t] != $s[$t+1] ? 1 : 0);
  781. break;
  782. case 10:
  783. $t--;
  784. $s[$t] = ($s[$t] < $s[$t+1] ? 1 : 0);
  785. break;
  786. case 11:
  787. $t--;
  788. $s[$t] = ($s[$t] >= $s[$t+1] ? 1 : 0);
  789. break;
  790. case 12:
  791. $t--;
  792. $s[$t] = ($s[$t] > $s[$t+1] ? 1 : 0);
  793. break;
  794. case 13:
  795. $t--;
  796. $s[$t] = ($s[$t] <= $s[$t+1] ? 1 : 0);
  797. break;
  798. case 14:
  799. echo "$s[$t] ";
  800. $t--;
  801. break;
  802. case 15:
  803. echo ($web ? "<br/>\n" : "\n");
  804. break;
  805. default:
  806. echo "!!HOUSTON, WE HAVE A PROBLEM!!" . ($web ? "<br/>\n" : "\n");
  807. break;
  808. }
  809. break;
  810. case "LOD":
  811. $t++;
  812. $s[$t] = $s[base($l, $b, $s) + $a];
  813. break;
  814. case "STO":
  815. $s[base($l, $b, $s) + $a] = $s[$t];
  816. $t--;
  817. break;
  818. case "CAL":
  819. $s[$t+1] = base($l, $b, $s);
  820. $s[$t+2] = $b;
  821. $s[$t+3] = $p;
  822. $b = $t + 1;
  823. $p = $a;
  824. break;
  825. case "INT":
  826. $t += $a;
  827. break;
  828. case "JMP":
  829. $p = $a;
  830. break;
  831. case "JPC":
  832. if ($s[$t] == $l)
  833. $p = $a;
  834. $t--;
  835. break;
  836. }
  837.  
  838. # print_stack($s, $b, $t);
  839. if ($p == 0)
  840. break;
  841. }
  842.  
  843. echo "End PL/0" . ($web ? "<br/>\n" : "\n");
  844. }
  845.  
  846. // display the web interface (prompt for source file)
  847. function show_intfc()
  848. {
  849. echo <<< END
  850. <html>
  851. <body>
  852. PL/0 Compiler+Interpreter<br/>
  853. v1.0 Beta<br/>
  854. 2009-04-11 (last mod: 2009-04-11)<p/>
  855.  
  856. <form method="post" enctype="multipart/form-data">
  857. <input type="hidden" name="data"/>
  858. PL/0 source file: <input type="file" name="file" size="80"/><p/>
  859. <input type="submit" value="Compile!"/>
  860. </form><p/>
  861. </body>
  862. </html>
  863. END;
  864. }
  865.  
  866. // MAIN
  867. // if we're accessed via the web, we get input through a form post
  868. if ($web)
  869. {
  870. // if we've got the source (via form submission)
  871. if (isset($_REQUEST["data"]) && $_FILES["file"]["name"] != "")
  872. {
  873. // and if the file exists on local disk
  874. if (file_exists($_FILES["file"]["tmp_name"]))
  875. {
  876. // get its contents and split into lines
  877. $file = str_replace("\r", "", file_get_contents($_FILES["file"]["tmp_name"]));
  878. $data = split("\n", $file);
  879. }
  880. // otherwise, bail!
  881. else
  882. {
  883. echo "ERROR: Unable to open " . $_FILES["file"]["name"] . "<br/>\n";
  884. }
  885. }
  886. // no submitted file? display the form
  887. else
  888. {
  889. show_intfc();
  890. }
  891. }
  892. // otherwise, get input from stdin
  893. else
  894. {
  895. // get the input and split into lines
  896. $file = str_replace("\r", "", file_get_contents("php://stdin"));
  897. //$data = split("\n", $file);
  898.  
  899. //REPLACED DEPRECATED SPLIT WITH NEW EXPLODE
  900. $data = explode("\n", $file);
  901. }
  902.  
  903. // PROGRAM
  904. getsym();
  905. block(0, 0);
  906. if ($sym != "PERIOD")
  907. error(5);
  908.  
  909. echo "Successful compilation!" . ($web ? "<p/>\n" : "\n\n");
  910. interpret();
  911.  
  912. ?>
  913.  
Success #stdin #stdout #stderr 0.03s 25760KB
stdin
CONST max = 100;
VAR inc;

PROCEDURE evens;
BEGIN
    inc := 0;
    WHILE inc < max DO
    BEGIN
        IF inc # 2 THEN ! inc;
        inc := inc + 1
    END
END;

CALL evens
.
stdout
CONST max = 100;
Identifier expected; got 
stderr
PHP Warning:  Creating default object from empty value in /home/cdbn9U/prog.php on line 80