home *** CD-ROM | disk | FTP | other *** search
/ ftp.cs.arizona.edu / ftp.cs.arizona.edu.tar / ftp.cs.arizona.edu / icon / historic / v941.tgz / icon.v941src.tar / icon.v941src / ipl / progs / pt.icn < prev    next >
Text File  |  2000-07-29  |  36KB  |  1,032 lines

  1. ############################################################################
  2. #
  3. #    File:     pt.icn
  4. #
  5. #    Subject:  Program to produce parse table generator
  6. #
  7. #    Author:   Deeporn H. Beardsley
  8. #
  9. #    Date:     December 10, 1988
  10. #
  11. ############################################################################
  12. #
  13. #   This file is in the public domain.
  14. #
  15. ############################################################################
  16. #
  17. #  See pt.man for a description of functionality as well as input and
  18. #  output format.
  19. #
  20. ############################################################################
  21.  
  22. #**********************************************************************
  23. #*                                                                    *
  24. #* Main procedure as well as                                          * 
  25. #*      a routine to generate production table, nonterminal, terminal *
  26. #*      and epsilon sets from the input grammar                       *
  27. #**********************************************************************
  28. #
  29. #  1.  Data structures:-
  30. #
  31. #       E.g.  Grammar:-
  32. #               
  33. #               A -> ( B )
  34. #               A -> B , C
  35. #               A -> a
  36. #               B -> ( C )
  37. #               B -> C , A
  38. #               B -> b
  39. #               C -> ( A )
  40. #               C -> A , B
  41. #               C -> c
  42. #
  43. #       prod_table                   prod
  44. #               __________________         _____  _____  _____  
  45. #               |     |          |     num | 1 |  | 2 |  | 3 |
  46. #               | "A" |    ------|-->[     |---| ,|---| ,|---| ]
  47. #               |     |          |     rhs |_|_|  |_|_|  |_|_|
  48. #               |     |          |           |      |      v  
  49. #               |     |          |           |      v      ["a"]
  50. #               |     |          |           v      ["B",",","C"]
  51. #               |     |          |           ["(","B",")"]
  52. #               |_____|__________|         _____  _____  _____  
  53. #               |     |          |     num | 4 |  | 5 |  | 6 |
  54. #               | "B" |    ------|-->[     |---| ,|---| ,|---| ]
  55. #               |     |          |     rhs |_|_|  |_|_|  |_|_|
  56. #               |     |          |           |      |      v  
  57. #               |     |          |           |      v      ["b"]
  58. #               |     |          |           v      ["C",",","A"]
  59. #               |     |          |           ["(","C",")"]
  60. #               |_____|__________|         _____  _____  _____  
  61. #               |     |          |     num | 7 |  | 8 |  | 9 |
  62. #               | "C" |    ------|-->[     |---| ,|---| ,|---| ]
  63. #               |     |          |     rhs |_|_|  |_|_|  |_|_|
  64. #               |     |          |           |      |      v  
  65. #               |     |          |           |      v      ["c"]
  66. #               |     |          |           v      ["A",",","B"]
  67. #               |     |          |           ["(","A",")"]
  68. #               ------------------
  69. #
  70. #               __________________
  71. #       firsts  | "A" |    ------|-->("(", "a", "b", "c")
  72. #               |-----|----------|
  73. #               | "B" |    ------|-->("(", "a", "b", "c")
  74. #               |-----|----------|
  75. #               | "C" |    ------|-->("(", "a", "b", "c")
  76. #               ------------------
  77. #
  78. #               _______
  79. #       NTs     |  ---|-->("A", "B", "C")
  80. #               -------
  81. #
  82. #               _______
  83. #       Ts      |  ---|-->("(", "a", "b", "c")
  84. #               -------
  85. #
  86. #  2.  Algorithm:-
  87. #
  88. #       get_productions() -- build productions table (& NT, T 
  89. #                       and epsilon sets):-
  90. #               open grammar file or from stdin
  91. #               while can get an input line, i.e. production, do
  92. #                 get LHS token and use it as entry value to table
  93. #                   (very first LHS token is start symbol of grammar)
  94. #                   (enter token in nonterminal, NT, set)
  95. #                 get each RHS token & form a list, put this list 
  96. #                   in the list, i.e.assigned value, of the table
  97. #                   (enter each RHS token in terminal, T, set)
  98. #                   (if first RHS token is epsilon
  99. #                      enter LHS token in the epsilon set)
  100. #               (T is the difference of T and NT)
  101. #               close grammar file
  102. #
  103. #**********************************************************************
  104. global prod_table, NTs, Ts, firsts, stateL, itemL
  105. global StartSymbol, start, eoi, epsilon
  106. global erratta            # to list all items in a state (debugging)
  107. record prod(num, rhs)           # assigned values for prod_table
  108. record arc(From, To)            # firsts computation -- closure
  109. record item(prodN, lhs, rhs1, rhs2, NextI)
  110. record state(C_Set, I_Set, goto)
  111. procedure main(opt_list)
  112.   local opt
  113.  
  114.   start := "START"              # start symbol for augmented grammar
  115.   eoi := "EOI"                  # end-of-input token (constant)
  116.   epsilon := "EPSILON"          # epsilon token (constant)
  117.   prod_table := table()         # productions
  118.   NTs := set()                  # non-terminals
  119.   Ts := set()                   # terminals
  120.   firsts := table()             # nonterminals only; first(T) = {T}
  121.   get_firsts(get_productions())
  122.   if /StartSymbol then exit(0)    # input file empty
  123.   write_prods()
  124.   if opt := (!opt_list == "-nt") then
  125.     write_NTs()
  126.   if opt := (!opt_list == "-t") then
  127.     write_Ts()
  128.   if opt := (!opt_list == "-f") then
  129.     write_firsts()
  130.   if opt := (!opt_list == "-e") then
  131.     erratta := 1  
  132.   else
  133.     erratta := 0  
  134.   stateL := list()              # not popped, only for referencing
  135.   itemL := list()               # not popped, only for referencing
  136.   state0()                      # closure of start production
  137.   gotos()                       # sets if items
  138.   p_table()                     # output parse table
  139. end
  140.  
  141. procedure get_productions()
  142.   local Epsilon_Set, LHS, first_RHS_token, grammarFile, line, prods, temp_list
  143.   local token, ws
  144.  
  145.   prods := 0                    # for enumeration of productions
  146.   ws := ' \t'
  147.   Epsilon_Set := set()          # NT's that have epsilon production
  148.   grammarFile := (open("grammar") | &input)
  149.   while line := read(grammarFile) do {
  150.     first_RHS_token := &null    # to detect epsilon production
  151.     temp_list := []             # RHS of production--list of tokens
  152.     line ? {
  153.       tab(many(ws))
  154.       LHS := tab(upto(ws))      # LHS of production--nonterminal
  155.       /firsts[LHS] := set()     
  156.       /StartSymbol := LHS       # start symbol for unaug. grammar
  157.       insert(NTs, LHS)          # collect nonterminals
  158.       tab(many(ws)); tab(match("->")); tab(many(ws))
  159.       while put(temp_list, token := tab(upto(ws))) do {
  160.         /first_RHS_token := token
  161.         insert(Ts, token)       # put all RHS tokens into T set for now
  162.         tab(many(ws))
  163.       }
  164.       token := tab(0)        # get last RHS non-ws token
  165.       if *token > 0 then {
  166.         put(temp_list, token)
  167.         /first_RHS_token := token
  168.         insert(Ts, token)
  169.       }
  170.       Ts --:= NTs               # set of terminals
  171.       delete(Ts, epsilon)    # EPSILON is not a terminal
  172.       /prod_table[LHS] := []
  173.       put(prod_table[LHS], prod(prods +:=1, temp_list))
  174.     }
  175.     if first_RHS_token == epsilon then
  176.       insert(Epsilon_Set, LHS)
  177.   }
  178.   if not (grammarFile === &input) then 
  179.     close(grammarFile)
  180.   return Epsilon_Set
  181. end
  182. #**********************************************************************
  183. #*                                                                    *
  184. #* Routines to generate first sets                                    *
  185. #**********************************************************************
  186. #  1.  Data structures:-
  187. #       (see also data structures in mainProds.icn)
  188. #
  189. #               __________________
  190. #       needs   | "A" |    ------|-->[B]
  191. #               |-----|----------|
  192. #               | "B" |    ------|-->[C]
  193. #               |-----|----------|
  194. #               | "C" |    ------|-->[A]
  195. #               ------------------
  196. #
  197. #       has_all_1st
  198. #               _______
  199. #               |  ---|-->("A", "C")
  200. #               -------
  201. #
  202. #
  203. #       G    |-----------------------| 
  204. #            |  __________________   v 
  205. #            |  | "A" |    ------|-->(B)<--------|
  206. #            |  |-----|----------|               |
  207. #            |--|---  |      ----|-->"A"         |
  208. #               |-----|----------|               |
  209. #               | "B" |    ------|-->(C)<-----|  |
  210. #               |-----|----------|            |  |
  211. #               | (C) |    ------|-->"B"      |  |
  212. #               |-----|----------|            |  |
  213. #               | "C" |    ------|-->(A)<--|  |  |
  214. #               |-----|----------|         |  |  |
  215. #               | (A) |    ------|-->"C"   |  |  |
  216. #               ------------------         |  |  |
  217. #                                          |  |  |
  218. #       closure_table                      |  |  |
  219. #               __________________         |  |  |
  220. #               | "A" |    ------|-->( ----| ,| ,| ) 
  221. #               |-----|----------|
  222. #               | "B" |    ------|-->( as above    )
  223. #               |-----|----------|
  224. #               | "C" |    ------|-->( as above    )
  225. #               ------------------
  226. #
  227. #       (Note: G table: the entry values (B) and (C) should be analogous
  228. #                       to that of '(A)'.)
  229. #
  230. #  2.  Algorithms:-
  231. #
  232. #       2.1  Firsts sets (note: A is nonterminal & 
  233. #                               beta is a string of symbols):-
  234. #                         For definition, see Aho, et al, Compilers...
  235. #                               Addison-Wesley, 1986, p.188)
  236. #               for each production A -> beta (use production table above)
  237. #                 loop1
  238. #                   case next RHS token, B, is
  239. #                     epsilon    :  do nothing, break from loop1
  240. #                     terminal   :  insert it in first(A), break from loop1
  241. #                     nonterminal:  put B in needs[A] table
  242. #                                   if B in epsilon set & last RHS token
  243. #                                     insert A in epsilon set
  244. #                                     break from loop1
  245. #                                   loop1
  246. #               collect has_all_1st set (NTs whose first is fully defined
  247. #                       i.e. NTs not entry value of needs table)
  248. #               Loop2 (fill_firsts)
  249. #                 for each NT B in each needs[A]
  250. #                   if B is in has_all_1st
  251. #                     insert all elements of first(B) in first(A)
  252. #                     delete B from needs[A]
  253. #                 if needs[A] is empty 
  254. #                   insert A in has_all_1st
  255. #                 if *has_all_1st set equal to *NTs set
  256. #                   exit loop2
  257. #                 if *has_all_1st set not equal to *NTs set
  258. #                   if *has_all_1st not changed from beginning of loop2
  259. #                   (i.e. circular dependency e.g.
  260. #                       needs[X] = [Y]
  261. #                       needs[Y] = [Z]
  262. #                       needs[Z] = [X])
  263. #                       find closure of each A
  264. #                       find a set of A's whose closure sets are same
  265. #                         pool their firsts together
  266. #                         add pooled firsts to first set of each A
  267. #                       goto loop2
  268. #
  269. #
  270. #               This algorithm is implemented by the following procedures:-
  271. #
  272. #                 get_firsts(Epsilon_Set) -- compute first sets of all
  273. #                    NTs, given the NTs that have epsilon productions.
  274. #
  275. #                 fill_firsts(needs) -- given the needs table that says
  276. #                    which first set contains the elements of other
  277. #                    first set(s), complete computation of first sets.
  278. #
  279. #                 buildgraph(tempL) -- given the productions in tempL,
  280. #                    build table G above.
  281. #
  282. #                 closure(G, S1, S2) -- given the productions in tempL,
  283. #                    the entry value S1 and its closure set S2, build 
  284. #                    closure_table.
  285. #
  286. #                 addnode(n, t) -- given table t ( G, actually), and
  287. #                    1. entry value of n, enter its assigned value in
  288. #                       in table t to be a set (empty, for now) 
  289. #                    2. use t[n] (in 1) as the entry value, enter its
  290. #                       assigned value in table t to be "n".
  291. #
  292. #                 closed_loop(G, SS, closure_table, tempL_i) -- given
  293. #                    table G, closure_table and a nonterminal tempL_i
  294. #                    that still needs its firsts completed, return the
  295. #                    set SS of nonterminals if each and every of these
  296. #                    nonterminals has identical closure set.
  297. #
  298. #                 finish_firsts(closed_set) -- given the set closed_set
  299. #                    of nonterminals where every member of of the set
  300. #                    has identical closure set, pool the elements 
  301. #                    (terminals) from their so-far known firsts sets
  302. #                    together and reenter this pooled value into their
  303. #                    firsts sets (firsts table).
  304. #
  305. #       2.2  Note that buildgraph(), closure() and addnode()
  306. #                 are either exactly or essentially the same as
  307. #                 given in class (by R. Griswold).
  308. #
  309. #**********************************************************************
  310.  
  311. procedure get_firsts(Epsilon_Set)
  312.   local needs, prods, i, j, k, token
  313.  
  314.   needs := table()
  315.   prods := sort(prod_table, 3)
  316.   every i := 1 to *prods by 2 do                # production(s) of a NT
  317.     every j := 1 to *prods[i+1] do              # RHS of each production
  318.       every k := 1 to *prods[i+1][j].rhs do     #  and each token
  319.         if ((token := prods[i+1][j].rhs[k]) == epsilon) then
  320.           break                                 # did in get_productions
  321.         else if member(Ts, token) then {        # leading token on RHS
  322.           insert(firsts[prods[i]], token)       # e.g. A -> ( B )
  323.           break
  324.         }
  325.         else { #if member(NTs, token) then      #      A -> B a C
  326.           /needs[prods[i]] := [] 
  327.           put(needs[prods[i]], token)
  328.           if not (member(Epsilon_Set, token)) then # not B -> EPSILON
  329.             break
  330.           if k = *prods[i+1][j].rhs then   # all RHS tokens are NTs &
  331.             insert(Epsilon_Set, prods[i])  # each has epsilon production
  332.         }
  333.   fill_firsts(needs)    # do firsts that contain firsts of other NT(s)
  334.   every insert(firsts[!Epsilon_Set], epsilon) # add epsilon last
  335. end
  336.  
  337. procedure fill_firsts(needs)
  338.   local G, L, NTy, SS, closed_set, closure_table, has_all_1st, i, lhs
  339.   local new_temp, rhs, size_has_all_1st, ss, ss_table, tempL, x
  340.  
  341.   closure_table := table()
  342.   has_all_1st := copy(NTs)              # set of NTs whose firsts fully defined
  343.   tempL := sort(needs, 3)
  344.   every i := 1 to *tempL by 2 do
  345.     delete(has_all_1st, tempL[i])
  346.   repeat {
  347.     ss := ""
  348.     ss_table := table()
  349.     size_has_all_1st := *has_all_1st
  350.     new_temp := list()
  351.     while lhs := pop(tempL) do {
  352.       rhs := pop(tempL)
  353.       L := list()
  354.       while NTy := pop(rhs) do
  355.         if NTy ~== lhs then
  356.           if member(has_all_1st, NTy) then
  357.             firsts[lhs] ++:= firsts[NTy]
  358.           else
  359.             put(L, NTy)
  360.       if *L = 0 then
  361.         insert(has_all_1st, lhs)
  362.       else {
  363.         put(new_temp, lhs)
  364.         put(new_temp, L)
  365.       }
  366.     }
  367.     tempL := new_temp
  368.     if *has_all_1st = *NTs then
  369.       break
  370.     if size_has_all_1st = *has_all_1st then {
  371.       G := buildgraph(tempL)
  372.       every i := 1 to *tempL by 2 do 
  373.         closure_table[tempL[i]] := closure(G, tempL[i])
  374.       every i := 1 to *tempL by 2 do {
  375.         closed_set := set()
  376.         SS := set([tempL[i]])
  377.         every x := !closure_table[tempL[i]] do
  378.           insert(SS, G[x])
  379.         closed_set := closed_loop(G,SS,closure_table,tempL[i])
  380.         if \closed_set then {
  381.           finish_firsts(closed_set) 
  382.           every insert(has_all_1st, !closed_set)
  383.           break
  384.         }
  385.       }
  386.     }
  387.   }
  388.   return
  389. end
  390.  
  391. procedure buildgraph(tempL)     # modified from the original version 
  392.   local arclist, nodetable, x, i
  393.  
  394.   arclist := []                 # by Ralph Griswold
  395.   nodetable := table()
  396.   every i := 1 to *tempL by 2 do {
  397.     every x := !tempL[i+1] do {
  398.      addnode(tempL[i], nodetable)
  399.      addnode(x, nodetable)
  400.      put(arclist, arc(tempL[i], x))
  401.     }
  402.   }
  403.   while x := get(arclist) do
  404.     insert(nodetable[x.From], nodetable[x.To])
  405.   return nodetable
  406. end
  407.  
  408. procedure closure(G, S1, S2)    # modified from the original version 
  409.   local S
  410.  
  411.   /S2 := set([G[S1]])           # by Ralph Griswold
  412.   every S := !(G[S1]) do
  413.     if not member(S2, S) then {
  414.       insert(S2, S)
  415.       closure(G, G[S], S2)
  416.     }
  417.   return S2
  418. end
  419.  
  420. procedure addnode(n, t)         # author: Ralph Griswold 
  421.   local S
  422.  
  423.   if /t[n] then {
  424.     S := set()
  425.     t[n] := S
  426.     t[S] := n
  427.   }
  428.   return
  429. end
  430.  
  431. procedure closed_loop(G, SS, closure_table, tempL_i)
  432.   local S, x, y
  433.  
  434.   delete(SS, tempL_i)
  435.   every x := !SS do {
  436.     S := set()
  437.     every y := !closure_table[x] do
  438.       insert(S, G[y])
  439.     delete(S, tempL_i)
  440.     if *S ~= *SS then fail
  441.     every y := !S do
  442.       if not member(SS, y) then fail
  443.   }
  444.   return insert(SS, tempL_i)
  445. end 
  446.  
  447. procedure finish_firsts(closed_set)
  448.   local S, x
  449.  
  450.   S := set()
  451.   every x := !closed_set do
  452.     every insert(S, !firsts[x]) 
  453.   every x := !closed_set do
  454.     every insert(firsts[x], !S)
  455. end
  456. #**********************************************************************
  457. #*                                                                    *
  458. #* Routines to generate states                                        *
  459. #**********************************************************************
  460. #
  461. #  1.  Data structures:-
  462. #
  463. #       E.g. Augmented grammar:-
  464. #       
  465. #               START -> S              (production 0)
  466. #               S -> ( S )              (production 1)
  467. #               S -> ( )                (production 2)
  468. #
  469. #             Item is a record of 5 fields:-
  470. #                 Example of an item: itemL[1] is [START->.S , $] 
  471. #                      prodN     represents the production number
  472. #                      lhs       represents the nonterminal at the
  473. #                                left hand side of the production
  474. #                      rhs1      represents the list of tokens seen so 
  475. #                                far (i.e. left of the dot in item)
  476. #                      rhs2      represents the list of tokens yet to be
  477. #                                seen (i.e. right of the dot in item)
  478. #                      NextI     represents the next input symbol
  479. #                                (the end of input symbol $ is 
  480. #                                represented by EOI.)
  481. #             
  482. #             
  483. #                  item             
  484. #                                _________       _________
  485. #                           prodN|   0   |       |   1   |
  486. #                                |-------|       |-------|
  487. #                           lhs  |"START"|       |  "S"  |
  488. #               _______          |-------|       |-------|     
  489. #       itemL   |  ---|-->[ rhs1 |    ---|---| , |  -----|---| , ...  ]
  490. #               -------          |-------|   |   |-------|   | 
  491. #                           rhs2 |    ---|-| |   |  -----|-| |
  492. #                                |-------| | |   |-------| | | 
  493. #                           NextI| "EOI" | | |   | "EOI" | | | 
  494. #                                --------- | |   --------- | | 
  495. #                                          | |             | | 
  496. #                                          | |             | |    
  497. #                                          | v             | v
  498. #                                          | []            | []
  499. #                                          |               |
  500. #                                          v               v
  501. #                                          ["S"]           ["(", "S", ")"]
  502. #
  503. #                 state
  504. #                                _______         
  505. #                           C_Set|  ---|-----|
  506. #               _______          |-----|     |
  507. #       stateL  |  ---|-->[ I_Set|  ---|---| |  , ...  ]
  508. #               -------          |-----|   | | 
  509. #                           goto |  ---|-| | |
  510. #                                ------- | | |
  511. #                                        | | v
  512. #                                        | | (1, 2, 3)
  513. #                                        | v        
  514. #                                        | (1)   
  515. #                                        v        
  516. #                                        __________________    
  517. #                                   | "A" |    5     |
  518. #                             |-----|----------|
  519. #                             | "B" |    2     |
  520. #                             |-----|----------|
  521. #                             | "C" |    3     |
  522. #                             ------------------
  523. #
  524. #
  525. #       (Note: 1.  The above 2 lists:-
  526. #                    -- are not to be popped
  527. #                    -- new elements are put in the back
  528. #                    -- index represents the identity of the element
  529. #                    -- no duplicate elements in either list
  530. #           2.  The state record:-
  531. #            I_Set represents J in function goto(I,x) in 
  532. #               Compiler, Aho, et al, Addison-Wesley, 1986,
  533. #              p. 232.
  534. #            C_Set represents the closure if I_Set.
  535. #            goto is part of the goto table and the shift 
  536. #              actions of the final parse table.)
  537. #              3.  The 1 in C_Set and I_Set in the diagrams above refer 
  538. #                       the same (physical) element.
  539. #
  540. #  2.  Algorithms:-
  541. #
  542. #         state0() -- create itemL[1] and stateL[1] as well as its
  543. #                       closure.
  544. #
  545. #         item_num(P_num, N_lhs, N_rhs1, N_rhs2, NI) --
  546. #                     if the item with the values given in the
  547. #                       argument list already exists in itemL list,
  548. #                       it returns the index of the item in the list,
  549. #                     if not, it builds a new item and put it at the 
  550. #                       end of the list and returns the new index.
  551. #
  552. #       prod_equal(prod1, prod2) --  prod1 and prod2 are lists of
  553. #              strings; fail if they are not the same.
  554. #
  555. #       state_closure(st) -- given the item set (I_set of the state 
  556. #              st), set the value of C_Set of st to the closure
  557. #              of this item set.  For definition of closure, 
  558. #                     see Aho, et al, Compilers..., Addison-Wesley, 
  559. #              1986, pp. 222-224)
  560. #              
  561. #       new_item(st,O_itm) -- given the state st and an item O_itm,
  562. #              suppose the item has the following configuration:-
  563. #                 [A -> B.CD,x]
  564. #              where CD is a string of terminal and nonterminal
  565. #              tokens.  If C is a nonterminal, 
  566. #                 for each C -> E in the grammar, and 
  567. #            for each y in first(Dx), add the new item
  568. #                 [C -> .E,y] 
  569. #            to the C_Set of st.
  570. #
  571. #       all_firsts(itm) -- given an item itm and suupose it has the
  572. #              following configuration:-
  573. #                 [A -> B.CD,x]
  574. #              where D is a string of terminal and nonterminal
  575. #              tokens.  The procedure returns first(Dx).
  576. #
  577. #       gotos() -- For definition of goto operation, see Aho, et al,
  578. #                    Compilers..., Addison-Wesley, 1986, pp. 224-227)
  579. #             The C = {closure({[S'->S]})} is set up by the
  580. #                    state0()
  581. #             call in the main procedure.
  582. #    
  583. #             It also compiles the goto table.  The errata part
  584. #             (last section of the code in this procedure) is
  585. #             for debugging purposes and is left intact for now.
  586. #              
  587. #       moved_item(itm) -- given the item itm and suppose it has the
  588. #              following configuration:-
  589. #                 [A -> B.CD,x]
  590. #              where D is a string of terminal and nonterminal
  591. #              tokens.  The procedure builds a new item:-
  592. #                 [A -> BC.D,x]
  593. #              It then looks up itemL to see if it already is
  594. #              in it.  If so, it'll return its index in the list,
  595. #              else, it'll put it in the back of the list and
  596. #              return this new index.  (This is done by calling
  597. #              item_num()).
  598. #              
  599. #       exists_I_Set(test) -- given the I_Set test, look in the stateL
  600. #             list and see if any state does contain similar
  601. #             I_Set, if so, return its index to the stateL list,
  602. #             else fail.
  603. #              
  604. #      set_equal(set1, set2) -- set1 and set2 are sets of integers;
  605. #              return set1 if the two sets have the same elements
  606. #              else fail.  (It is used strictly in comparison of
  607. #              I_Sets).
  608. #
  609. #
  610. #**********************************************************************
  611.  
  612. procedure state0()
  613.   local itm, st
  614.  
  615.   itm := item_num(0, start, [], [StartSymbol], eoi)
  616.   st := state(set(), set([itm]), table())
  617.   put(stateL, st)
  618.   state_closure(st)     # closure on initial state
  619. end
  620.  
  621. procedure item_num(P_num, N_lhs, N_rhs1, N_rhs2, NI)
  622.   local itm, i
  623.  
  624.   itm := item(P_num, N_lhs, N_rhs1, N_rhs2, NI)
  625.   every i := 1 to *itemL do {
  626.     if itm.prodN ~== itemL[i].prodN then next
  627.     if itm.lhs ~== itemL[i].lhs then next
  628.     if not prod_equal(itm.rhs1, itemL[i].rhs1) then next
  629.     if not prod_equal(itm.rhs2, itemL[i].rhs2) then next
  630.     if itm.NextI == itemL[i].NextI then return i
  631.   }
  632.   put(itemL, itm)
  633.   return *itemL
  634. end
  635.  
  636. procedure prod_equal(prod1, prod2)      # compare 2 lists of strings
  637.   local i
  638.  
  639.   if *prod1 ~= *prod2 then fail
  640.   every i := 1 to *prod1 do
  641.     if prod1[i] ~== prod2[i] then fail
  642.   return
  643. end
  644.  
  645. procedure state_closure(st)
  646.   local addset, more_set, i
  647.  
  648.   st.C_Set := copy(st.I_Set)
  649.   addset := copy(st.C_Set)
  650.   while *addset > 0 do {
  651.     more_set := set()
  652.     every i := !addset do
  653.       if (itemL[i].rhs2[1] ~== epsilon) then
  654.         if member(NTs, itemL[i].rhs2[1]) then
  655.           more_set ++:= new_item(st,itemL[i])
  656.     addset := more_set
  657.   }
  658. end
  659.  
  660. procedure new_item(st,O_itm)
  661.   local N_Lhs, N_Rhs1, N_prod, NxtInput, T_itm, i, rtn_set
  662.   rtn_set := set()
  663.   NxtInput := all_firsts(O_itm)
  664.   N_Lhs := O_itm.rhs2[1]
  665.   N_Rhs1 := []
  666.   every N_prod := !prod_table[N_Lhs] do
  667.     every i := !NxtInput do {
  668.       T_itm := item_num(N_prod.num, N_Lhs, N_Rhs1, N_prod.rhs, i)
  669.       if not member(st.C_Set, T_itm) then {
  670.         insert(st.C_Set, T_itm)
  671.         insert(rtn_set, T_itm)
  672.       }
  673.     }
  674.   return rtn_set
  675. end
  676.  
  677. procedure all_firsts(itm)
  678.   local rtn_set, i
  679.  
  680.   if *itm.rhs2 = 1 then
  681.     return set([itm.NextI])
  682.   rtn_set := set()
  683.   every i := 2 to *itm.rhs2 do
  684.     if member(Ts, itm.rhs2[i]) then 
  685.       return insert(rtn_set, itm.rhs2[i])
  686.     else {
  687.       rtn_set ++:= firsts[itm.rhs2[i]]
  688.       if not member(firsts[itm.rhs2[i]], epsilon) then
  689.         return rtn_set
  690.     }
  691.   return insert(rtn_set, itm.NextI)
  692. end
  693.  
  694. procedure gotos()
  695.   local New_I_Set, gost, i, i_num, j, j_num, looked_at, scan, st, st_num, x
  696.   st_num := 1
  697.   repeat{
  698.     looked_at := set()
  699.     scan := sort(stateL[st_num].C_Set)
  700.     every i := 1 to *scan do {
  701.       i_num := scan[i]
  702.       if member(looked_at, i_num) then next
  703.       insert(looked_at, i_num)
  704.       x := itemL[i_num].rhs2[1]         # next LHS
  705.       if ((*itemL[i_num].rhs2 = 0) | (x == epsilon)) then next
  706.       New_I_Set := set([moved_item(itemL[i_num])])
  707.       every j := i+1 to *scan do {
  708.         j_num := scan[j]
  709.         if not member(looked_at, j_num) then
  710.           if (x == itemL[j_num].rhs2[1]) then {
  711.             insert(New_I_Set, moved_item(itemL[j_num]))
  712.             insert(looked_at, j_num)
  713.           }
  714.       }
  715.       if gost := exists_I_Set(New_I_Set) then 
  716.         stateL[st_num].goto[x] := gost    #add into goto
  717.       else { # add a new state
  718.         st := state(set(), New_I_Set, table())
  719.         put(stateL, st)
  720.         state_closure(st)
  721.         stateL[st_num].goto[x] := *stateL    #add into goto
  722.       }
  723.     }
  724.     if erratta=1 then {
  725.       write("--------------------------------")
  726.       write("State ", st_num-1)
  727.       write_state(stateL[st_num])
  728.     }
  729.     st_num +:= 1
  730.     if st_num > *stateL then {
  731.       if erratta=1 then
  732.         write("--------------------------------")
  733.       return stateL
  734.     }
  735.   }
  736. end
  737.  
  738. procedure moved_item(itm)
  739.   local N_Rhs1, N_Rhs2, i
  740.  
  741.   N_Rhs1 := copy(itm.rhs1)
  742.   put(N_Rhs1, itm.rhs2[1])
  743.   N_Rhs2 := list()
  744.   every i := 2 to *itm.rhs2 do
  745.     put(N_Rhs2, itm.rhs2[i])
  746.   return item_num(itm.prodN, itm.lhs, N_Rhs1, N_Rhs2, itm.NextI)
  747. end
  748.  
  749. procedure exists_I_Set(test)
  750.   local st
  751.  
  752.   every st := 1 to *stateL do
  753.     if set_equal(test, stateL[st].I_Set) then return st
  754.   fail
  755. end
  756.  
  757. procedure set_equal(set1, set2)         
  758.   local i
  759.  
  760.    if *set1 ~= *set2 then fail
  761.    every i := !set2 do
  762.      if not member(set1, i) then fail
  763.    return set1
  764. end
  765. #**********************************************************************
  766. #*                                                                    *
  767. #* Miscellaneous write routines                                       *
  768. #**********************************************************************
  769. #    The following are write routines; some for optional output
  770. #    while others are for debugging purposes. 
  771. #        write_item(itm) -- write the contents if item itm.
  772. #        write_state(st) -- write the contents of state st.
  773. #        write_tbl_list(out) -- (for debugging purposes only).
  774. #        write_prods()-- write the enmnerated grammar productions.
  775. #        write_NTs() -- write the set of nonterminals.
  776. #        write_Ts() -- write the set of terminals.
  777. #        write_firsts() -- write the first sets of each nonterminal.
  778. #        write_needs(L) -- write the list of all nonterminals and the
  779. #                  associated nonterminals whose first sets 
  780. #                  it still needs to compute its own first
  781. #                  set.
  782. #**********************************************************************
  783.  
  784. procedure write_item(itm)
  785.   local i
  786.  
  787.   writes("[(",itm.prodN,") ",itm.lhs," ->")
  788.   every i := !itm.rhs1 do writes(" ",i)
  789.   writes(" .")
  790.   every i := !itm.rhs2 do writes(" ",i)
  791.   writes(", ",itm.NextI,"]\n")
  792. end
  793.  
  794. procedure write_state(st)
  795.   local i, tgoto
  796.  
  797.   write("I_Set")
  798.   every i := ! st.I_Set do {
  799.     writes("Item ", i, " ")
  800.     write_item(itemL[i])
  801.   }
  802.   write()
  803.   write("C_Set")
  804.   every i := ! st.C_Set do {
  805.     writes("Item ", i, " ")
  806.     write_item(itemL[i])
  807.   }
  808.   tgoto := sort(st.goto, 3)
  809.   write()
  810.   write("Gotos")
  811.   every i := 1 to *tgoto by 2 do
  812.     write("Goto state ", tgoto[i+1]-1, " on ", tgoto[i])
  813. end
  814.  
  815. procedure write_tbl_list(out)
  816.   local i, j
  817.  
  818.   every i := 1 to *out by 2 do {
  819.     writes(out[i], ", [")
  820.     every j := *out[i+1] do {
  821.       if j ~= 1 then
  822.         writes(", ")
  823.       writes(out[i+1][j])
  824.     }
  825.     writes("]\n")
  826.   }
  827. end
  828.  
  829. procedure write_prods()
  830.   local i, j, k, prods
  831.  
  832.   prods := sort(prod_table, 3)
  833.   every i := 1 to *prods by 2 do 
  834.     every j := 1 to *prods[i+1] do {
  835.       writes(right(string(prods[i+1][j].num),3," "),":  ")
  836.       writes(prods[i], " ->")
  837.       every k := 1 to *prods[i+1][j].rhs do
  838.         writes(" ", prods[i+1][j].rhs[k])
  839.       writes("\n")
  840.     }
  841. end
  842.  
  843. procedure write_NTs()
  844.   local temp_list
  845.  
  846.   temp_list := sort(NTs)
  847.   write("\n")
  848.   write("nonterminal sets are:")
  849.   every write(|pop(temp_list))
  850. end
  851.  
  852. procedure write_Ts()
  853.   local temp_list
  854.  
  855.   temp_list := sort(Ts)
  856.   write("\n")
  857.   write("terminal sets are:")
  858.   every write(|pop(temp_list))
  859. end
  860.  
  861. procedure write_firsts()
  862.   local temp_list, i, j, first_list
  863.  
  864.   temp_list := sort(firsts, 3)
  865.   write("\nfirst sets:::::")
  866.   every i := 1 to *temp_list by 2 do {
  867.     writes(temp_list[i], ": ")
  868.     first_list := sort(temp_list[i+1])
  869.     every j := 1 to *first_list do
  870.       writes(" ", pop(first_list))
  871.     writes("\n\n")
  872.   }
  873. end
  874.  
  875. procedure write_needs(L)
  876.   local i, temp
  877.  
  878.   write("tempL : ")
  879.   every i := 1 to *L by 2 do {
  880.     writes(L[i], " ")
  881.     temp := copy(L[i+1])
  882.     every writes(|pop(temp))
  883.     writes("\n")
  884.   }
  885. end
  886. #**********************************************************************
  887. #*                                                                    *
  888. #* Output the parse table routines                                    *
  889. #**********************************************************************
  890. #
  891. #    p_table() -- output parse table: tablulated (vertical and
  892. #             horizontal lines, etc.) if the width is within
  893. #             80 characters long else a listing.
  894. #
  895. #    outline(size, out, st_num, T_list, NT_list) -- print the header;
  896. #             used in table form.
  897. #
  898. #    border(size, T_list, NT_list, col) -- draw a horizontal line
  899. #             for the table form, given the table size that tells
  900. #             the length of each token given the lists of 
  901. #             terminals and nonterminals.  If the line is the 
  902. #             last line of the table, col given is "-", else it 
  903. #             is "-". 
  904. #
  905. #    outstate(st, out, T_list, NT_list) -- print the shift, reduce
  906. #             and goto for state st from information given in
  907. #             out, and the lists of terminals and nonterminals;
  908. #             used to output the parse table in the listing form.
  909. #
  910. #**********************************************************************
  911.  
  912. procedure p_table()
  913.   local NT_list, T_list, action, gs, i, itm, msize, out, s, size, st_num, tsize
  914.  
  915.   T_list := sort(Ts)
  916.   put(T_list, eoi)
  917.   NT_list := sort(NTs)
  918.   size := table()
  919.   out := table()
  920.   if *stateL < 1000 then msize := 4
  921.   else if *stateL < 10000 then msize := 5
  922.   else msize := 6
  923.   tsize := 7
  924.   every s := !T_list do {
  925.     size[s] := *s
  926.     size[s] <:= msize
  927.     tsize +:= size[s] + 3
  928.     out[s] := s
  929.   }
  930.   every s := !NT_list do {
  931.     size[s] := *s
  932.     size[s] <:= msize
  933.     tsize +:= size[s] + 3
  934.     out[s] := s
  935.   }
  936.   write()
  937.   write()
  938.   write("PARSE TABLE")
  939.   write()
  940.   if tsize <= 80 then {
  941.     outline(size, out, 0, T_list, NT_list)
  942.     border(size, T_list, NT_list, "+")
  943.   }
  944.   every st_num := 1 to *stateL do {
  945.     out := table()
  946.     gs := sort(stateL[st_num].goto,3)
  947.     every i := 1 to * gs by 2 do {  # do the shifts and gotos
  948.       if member(Ts, gs[i]) then
  949.         out[gs[i]] := "S" || string(gs[i+1]-1)    # shift (action table)
  950.       else
  951.         out[gs[i]] := string(gs[i+1]-1)        # for goto table
  952.     }
  953.     every itm := itemL[!stateL[st_num].C_Set] do {
  954.       if ((*itm.rhs2 = 0) | (itm.rhs2[1] == epsilon))  then {
  955.         if itm.prodN = 0 then
  956.           action := "ACC"            # accept state
  957.         else
  958.           action := "R" || string(itm.prodN)    # reduce (action table)
  959.         if /out[itm.NextI] then
  960.           out[itm.NextI] := action
  961.         else { # conflict
  962.           write(&errout, "Conflict on state ", st_num-1, " symbol ",
  963.            itm.NextI, " between ", action, " and ", out[itm.NextI])
  964.           write(&errout, "  ", out[itm.NextI], " takes presidence")
  965.         }
  966.       }
  967.     }
  968.     if tsize <= 80 then
  969.       outline(size, out, st_num, T_list, NT_list)
  970.     else
  971.       outstate(st_num, out, T_list, NT_list)
  972.   }
  973. end
  974.  
  975. procedure outline(size, out, st_num, T_list, NT_list)
  976.   local s
  977.  
  978.   if st_num = 0 then
  979.     writes("State")
  980.   else
  981.     writes(right(string(st_num-1),5," "))
  982.   writes(" ||")
  983.   every s := !T_list do {
  984.     /out[s] := ""
  985.     writes(" ", center(out[s],size[s]," "), " |")
  986.   }
  987.   writes("|")
  988.   every s := !NT_list do {
  989.     /out[s] := ""
  990.     writes(" ", center(out[s],size[s]," "), " |")
  991.   }
  992.   write()
  993.   if st_num < * stateL then
  994.     border(size, T_list, NT_list, "+")
  995.   else
  996.     border(size, T_list, NT_list, "-")
  997. end
  998.  
  999. procedure border(size, T_list, NT_list, col)
  1000.   local s
  1001.  
  1002.   writes("------", col, col)
  1003.   every s := !T_list do
  1004.     writes("-", center("",size[s],"-"),"-", col)
  1005.   writes(col)
  1006.   every s := !NT_list do
  1007.     writes("-",center("",size[s],"-"), "-", col)
  1008.   writes("\n")
  1009. end
  1010.  
  1011. procedure outstate(st, out, T_list, NT_list)
  1012.   local s
  1013.  
  1014.   write()
  1015.   write("Actions for state ", st-1)
  1016.   every s := !T_list do
  1017.     if \out[s] then
  1018.       if out[s][1] == "R" then
  1019.         write("   On ", s, " reduce by production ", out[s][2:0])
  1020.       else if out[s][1] == "A" then
  1021.     write("   On ", s, " ACCEPT")
  1022.       else
  1023.         write("   On ", s, " shift to state ", out[s][2:0])
  1024.   every s := !NT_list do
  1025.     if \out[s] then
  1026.       write("   On ", s, " Goto ", out[s])
  1027.   write()
  1028. end
  1029.  
  1030.