home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk1.iso / altsrc / articles / 11185 < prev    next >
Text File  |  1994-08-27  |  32KB  |  1,253 lines

  1. Newsgroups: alt.sources
  2. Path: wupost!howland.reston.ans.net!vixen.cso.uiuc.edu!uchinews!quads!goer
  3. From: goer@quads.uchicago.edu (Richard L. Goerwitz)
  4. Subject: IBPAG2, part 06
  5. Message-ID: <1994Aug28.042130.25218@midway.uchicago.edu>
  6. Sender: news@uchinews.uchicago.edu (News System)
  7. Reply-To: goer@midway.uchicago.edu
  8. Organization: University of Chicago
  9. References: <1994Aug28.041715.24693@midway.uchicago.edu>
  10. Date: Sun, 28 Aug 1994 04:21:30 GMT
  11. Lines: 1240
  12.  
  13. #!/bin/sh
  14. # this is part 6 of a multipart archive
  15. # do not concatenate these parts, unpack them in order with /bin/sh
  16. # file iiglrpar.lib continued
  17. #
  18. CurArch=6
  19. if test ! -r s2_seq_.tmp
  20. then echo "Please unpack part 1 first!"
  21.      exit 1; fi
  22. ( read Scheck
  23.   if test "$Scheck" != $CurArch
  24.   then echo "Please unpack part $Scheck next!"
  25.        exit 1;
  26.   else exit 0; fi
  27. ) < s2_seq_.tmp || exit 1
  28. sed 's/^X//' << 'SHAR_EOF' >> iiglrpar.lib
  29. X            }
  30. X            if find("isolate", tmp) then {
  31. X                # Prune all but the current parser.
  32. X            $$ifdef IIDEBUG
  33. X                write(&errout, "+++ isolating by pruning")
  34. X                while p := pop(actives) do
  35. X                $iidebug("p", token, ruleno, p)
  36. X                while p := pop(reducers) do
  37. X                $iidebug("p", token, ruleno, p)
  38. X                while p := pop(shifters) do
  39. X                $iidebug("p", token, ruleno, p)
  40. X                while p := pop(barfers) do
  41. X                $iidebug("p", token, ruleno, p)
  42. X            $$else
  43. X                while pop(actives)
  44. X                while pop(reducers)
  45. X                while pop(shifters)
  46. X                while pop(barfers)
  47. X            $$endif    #IIDEBUG
  48. X            }
  49. X            if find("accept", tmp) then {
  50. X                $iidebug("a", token, ruleno, parser)
  51. X                suspend arglist[-1] | &null
  52. X                next
  53. X            }
  54. X            }
  55. X            # Finally, push the result!
  56. X            result := arglist[-1] | &null
  57. X            push(parser.value_stack, result)
  58. X            $iidebug("r", token, ruleno, parser)
  59. X            put(actives, parser)
  60. X        }
  61. X        }
  62. X        # If there is no action code for this rule...
  63. X        else {
  64. X        # ...push the value of the last RHS arg.
  65. X        # For 0-length e-productions, push &null.
  66. X        result := arglist[-1] | &null
  67. X        push(parser.value_stack, result)
  68. X        $iidebug("r", token, ruleno, parser)
  69. X        put(actives, parser)
  70. X        }
  71. X    }
  72. X    }
  73. X
  74. Xend
  75. X
  76. X
  77. X#
  78. X# perform_shifts
  79. X#
  80. Xprocedure $perform_shifts(token, actives, shifters)
  81. X    
  82. X    local parser, ruleno
  83. X
  84. X    *shifters = 0 & fail
  85. X
  86. X    while parser := pop(shifters) do {
  87. X    #
  88. X    # One of the iidirectives is iiclearin, i.e. clear the input
  89. X    # token and try again on the next token.
  90. X    #
  91. X    \parser.clearin := &null & {
  92. X        put(actives, parser)
  93. X        next
  94. X    }
  95. X    parser.action ? {
  96. X        #
  97. X            # Shift action format, e.g. s2.1 = shift and go to state 2
  98. X        # by rule 1.
  99. X            #
  100. X        move(1)
  101. X        push(parser.state_stack, integer(tab(find("."))))
  102. X        push(parser.value_stack, $iilval)
  103. X        ="."; ruleno := integer(tab(many(&digits)))
  104. X        pos(0) | stop("malformed action:  ", act)
  105. X        #
  106. X        # If, while recovering, we can manage to shift 3 tokens,
  107. X        # then we consider ourselves resynchronized.  Don't count
  108. X        # the error token (-1).
  109. X        #
  110. X        if token ~= -1 then {
  111. X        if \parser.recover_shifts +:= 1 then {
  112. X            # 3 shifts make a successful recovery
  113. X            if parser.recover_shifts > 4 then {
  114. X            parser.recover_shifts := &null
  115. X            parser.discards := 0
  116. X            }
  117. X        }
  118. X        }
  119. X        $iidebug("s", token, ruleno, parser)
  120. X    }
  121. X    put(actives, parser)
  122. X    }
  123. X
  124. X    return
  125. X    
  126. Xend
  127. X
  128. X
  129. X#
  130. X# perform_barfs
  131. X#
  132. Xprocedure $perform_barfs(atbl, token, actives, barfers, fail_on_error)
  133. X
  134. X    #
  135. X    # Note how this procedure has its own local reducers and shifters
  136. X    # list.  These are *not* passed from the parent environment!
  137. X    #
  138. X    local parser, count, reducers, shifters, recoverers
  139. X
  140. X    # To hold the list of parsers that need to shift error (-1).
  141. X    recoverers := list()
  142. X
  143. X    count := 0
  144. X    while parser := pop(barfers) do {
  145. X    count +:= 1
  146. X    if \parser.recover_shifts := 0 then {
  147. X        #
  148. X        # If we're already in an error state, discard the
  149. X        # current token, and increment the number of discards
  150. X        # we have made.  500 is too many; abort.
  151. X        #
  152. X        if (parser.discards +:= 1) > 500 then {
  153. X        if proc($iierror)
  154. X        then $iierror("fatal error: can't resynchronize")
  155. X        else write(&errout, "fatal error: can't resynchronize")
  156. X        if \fail_on_error then fail
  157. X        else stop()
  158. X        }
  159. X        # try again on this one with the next token
  160. X        put(actives, parser)
  161. X    } else {
  162. X        parser.errors +:= 1 # error count for this parser
  163. X        parser.discards := parser.recover_shifts := 0
  164. X        # If this is our first erroneous parser, print a message.
  165. X        if count = 1 then {
  166. X        if proc($iierror)
  167. X        then $iierror(image(\$ttbl[token]) | image(token))
  168. X        else write(&errout, "parse error")
  169. X        }
  170. X        #
  171. X        # If error appears in a RHS, pop states until we get to a
  172. X        # spot where error (-1) is a valid lookahead token:
  173. X        #
  174. X        if \$ttbl[-1] then {
  175. X        until *parser.state_stack = 0 do {
  176. X            if \atbl[-1][parser.state_stack[1]] then {
  177. X            put(recoverers, parser)
  178. X            break next
  179. X            } else pop(parser.state_stack) & pop(parser.value_stack)
  180. X        }
  181. X        }
  182. X        # If we get past here, the stack is now empty or there
  183. X        # are no error productions.  Abandon this parser.
  184. X        $iidebug("p", token, &null, parser)
  185. X    }
  186. X    }
  187. X
  188. X    # Parsers still recovering are in the actives list; those that
  189. X    # need to shift error (-1) are in the recoverers list.  The
  190. X    # following turns recoverers into actives:
  191. X    #
  192. X    if *recoverers > 0 then {
  193. X    reducers := list()    # a scratch list
  194. X    shifters := list()    # ditto
  195. X    until *recoverers = *reducers = 0 do {
  196. X        $$ifdef AUTO_PRUNE
  197. X        auto_prune(actives)
  198. X        $$endif
  199. X        suspend $ib_action(atbl, -1, recoverers, shifters,
  200. X                   reducers, barfers)
  201. X        suspend $perform_reductions(-1, recoverers, shifters,
  202. X                    reducers, barfers)
  203. X    }
  204. X    $perform_shifts(-1, recoverers, shifters)
  205. X    every put(actives, !recoverers)
  206. X    }
  207. X    #
  208. X    # If there were no recoverers, we've already shifted the error
  209. X    # token, and are discarding tokens from the input stream.  Note
  210. X    # that if one parser was recovering, they *all* should be
  211. X    # recovering, since if one was not recovering, it the erroneous
  212. X    # parsers should all have been discarded by the calling proc.
  213. X    #
  214. X    else
  215. X    $discard_token := 1
  216. X
  217. Xend
  218. X
  219. X
  220. X$$ifdef IIDEBUG
  221. X
  222. Xrecord production(LHS, RHS, POS, LOOK, no, prec, assoc)
  223. X#
  224. X# iidebug
  225. X#
  226. Xprocedure $iidebug(action, token, ruleno, parser)
  227. X
  228. X    local p, t, state
  229. X    static rule_list
  230. X    initial {
  231. X    rule_list := $rule_list_insertion_point
  232. X    $$line 693 "iiglrpar.lib"
  233. X    }
  234. X
  235. X    write(&errout, "---  In parser ", image(parser), ":")
  236. X    case action of {
  237. X    "a"     : writes(&errout, "accepting ")    &
  238. X        state := parser.state_stack[1]
  239. X    "e"     : writes(&errout, "***ERROR***\n") &
  240. X          write(&errout, "recover shifts = ",
  241. X             parser.recover_shifts) &
  242. X          write(&errout, "discarded tokens = ",
  243. X             parser.discards) &
  244. X              writes(&errout, "error action ") &
  245. X        state := parser.state_stack[1]
  246. X    "p"     : writes(&errout, "***PRUNING***\n") &
  247. X              writes(&errout, "prune action ") &
  248. X        state := parser.state_stack[1]
  249. X    "r"     : writes(&errout, "reducing ")     &
  250. X        state := parser.state_stack[2]
  251. X    "s"     : writes(&errout, "shifting ")     &
  252. X        state := parser.state_stack[2]
  253. X    default : stop("malformed action argument to iidebug")
  254. X    }
  255. X
  256. X    t := image(token) || (" (" || (\$ttbl[token] | "unknown") || ")")
  257. X    writes(&errout, "on lookahead ", t, ", in state ", state)
  258. X    if \ruleno then {
  259. X    (p := !rule_list).no === ruleno &
  260. X        write(&errout, "; rule ", $production_2_string(p, $ttbl))
  261. X    }
  262. X    # for errors, ruleno is null
  263. X    else write(&errout)
  264. X
  265. X    write(&errout, "    state stack now: ")
  266. X    every write(&errout, "\t", image(!parser.state_stack))
  267. X    write(&errout, "    value stack now: ")
  268. X    if *parser.value_stack > 0
  269. X    then every write(&errout, "\t", image(!parser.value_stack))
  270. X    else write(&errout, "\t(empty)")
  271. X
  272. X    return
  273. X
  274. Xend
  275. X
  276. X
  277. X#
  278. X# production_2_string:  production record -> string
  279. X#                       p                 -> s
  280. X#
  281. X#     Stringizes an image of the LHS and RHS of production p in
  282. X#     human-readable form.
  283. X#
  284. Xprocedure $production_2_string(p, ibtoktbl)
  285. X
  286. X    local s, m, t
  287. X
  288. X    s := image(p.LHS) || " -> "
  289. X    every m := !p.RHS do {
  290. X    if t := \ (\ibtoktbl)[m]
  291. X    then s ||:= t || " "
  292. X    else s ||:= image(m) || " "
  293. X    }
  294. X    # if the POS field is nonnull, print it
  295. X    s ||:= "(POS = " || image(\p.POS) || ") "
  296. X    # if the LOOK field is nonnull, print it, too
  297. X    s ||:= "lookahead = " || image(\p.LOOK)
  298. X
  299. X    return trim(s)
  300. X
  301. Xend
  302. X
  303. X#
  304. X# show_new_forest
  305. X#
  306. Xprocedure show_new_forest(msg, actives, shifters, reducers, barfers, parser)
  307. X    write(&errout, msg)
  308. X    write(&errout, "    List of active parsers:")
  309. X    every write(&errout, "\t", image(!actives))
  310. X    every write(&errout, "\t", image(!shifters))
  311. X    every write(&errout, "\t", image(!reducers))
  312. X    every write(&errout, "\t", image(!barfers), " (error)")
  313. X    write(&errout, "\tnew -> ", image(parser))
  314. Xend
  315. X$$endif                # IIDEBUG
  316. X
  317. X
  318. X$$ifdef COMPRESSED_TABLES
  319. X
  320. X#
  321. X# uncompress_action
  322. X#
  323. Xprocedure $uncompress_action()
  324. X
  325. X    local next_chunk, full_action
  326. X
  327. X    next_chunk := create ord(!&subject[&pos:0])
  328. X    case $in_ib_bits(next_chunk, 2) of {
  329. X    0: {
  330. X        full_action := "s"
  331. X        full_action ||:= $in_ib_bits(next_chunk, 11)
  332. X        full_action ||:= "."
  333. X        full_action ||:= $in_ib_bits(next_chunk, 11)
  334. X        move(3)
  335. X    }
  336. X    1: {
  337. X        full_action := "r"
  338. X        full_action ||:= $in_ib_bits(next_chunk, 11)
  339. X        full_action ||:= "<"
  340. X        full_action ||:= $in_ib_bits(next_chunk, 11)
  341. X        full_action ||:= ">"
  342. X        full_action ||:= $in_ib_bits(next_chunk, 8)
  343. X        move(4)
  344. X    }
  345. X        2: {
  346. X        full_action := "a"
  347. X        move(1)
  348. X    }
  349. X    } | fail
  350. X
  351. X    return full_action
  352. X
  353. Xend
  354. X
  355. X
  356. X#
  357. X# in_ib_bits:  like inbits (IPL), but with coexpression for file
  358. X#
  359. Xprocedure $in_ib_bits(next_chunk, len)
  360. X
  361. X    local i, byte, old_byte_mask
  362. X    static old_byte, old_len, byte_length
  363. X    initial {
  364. X    old_byte := old_len := 0
  365. X    byte_length := 8
  366. X    }
  367. X
  368. X    old_byte_mask := (0 < 2^old_len - 1) | 0
  369. X    old_byte := iand(old_byte, old_byte_mask)
  370. X    i := ishift(old_byte, len-old_len)
  371. X
  372. X    len -:= (len > old_len) | {
  373. X    old_len -:= len
  374. X    return i
  375. X    }
  376. X    
  377. X    while byte := @next_chunk do {
  378. X    i := ior(i, ishift(byte, len-byte_length))
  379. X    len -:= (len > byte_length) | {
  380. X        old_len := byte_length-len
  381. X        old_byte := byte
  382. X        return i
  383. X    }
  384. X    }
  385. X
  386. Xend
  387. X
  388. X$$endif                # COMPRESSED_TABLES
  389. X
  390. X#
  391. X# fullcopy:  make full recursive copy of object obj
  392. X#
  393. Xprocedure $fullcopy(obj)
  394. X
  395. X    local retval, i, k
  396. X
  397. X    case type(obj) of {
  398. X        "co-expression"  : return obj
  399. X        "cset"           : return obj
  400. X        "file"           : return obj
  401. X        "integer"        : return obj
  402. X        "list"           : {
  403. X            retval := list(*obj)
  404. X            every i := 1 to *obj do
  405. X                retval[i] := $fullcopy(obj[i])
  406. X            return retval
  407. X        }
  408. X        "null"           :  return &null
  409. X        "procedure"      :  return obj
  410. X        "real"           :  return obj
  411. X        "set"            :  {
  412. X            retval := set()
  413. X            every insert(retval, $fullcopy(!obj))
  414. X            return retval
  415. X        }
  416. X        "string"         :  return obj
  417. X        "table"          :  {
  418. X            retval := table(obj[[]])
  419. X            every k := key(obj) do
  420. X                insert(retval, $fullcopy(k), $fullcopy(obj[k]))
  421. X            return retval
  422. X        }
  423. X        # probably a record; if not, we're dealing with a new
  424. X        # version of Icon or a nonstandard implementation, and
  425. X    # we're screwed
  426. X        default          :  {
  427. X            retval := copy(obj)
  428. X            every i := 1 to *obj do
  429. X                retval[i] := $fullcopy(obj[i])
  430. X            return retval
  431. X        }
  432. X    }
  433. X
  434. Xend
  435. X
  436. X
  437. X$$ifdef AUTO_PRUNE
  438. Xprocedure auto_prune(actives)
  439. X
  440. X    new_actives := []
  441. X    while parser1 := pop(actives) do {
  442. X    every parser2 := actives[j := 1 to *actives] do {
  443. X        parser1.state_stack[1] = parser2.state_stack[1] | next
  444. X        *parser1.value_stack   = *parser2.value_stack   | next
  445. X        every i := 1 to *parser1.value_stack do {
  446. X        parser1.value_stack[i] === parser2.value_stack[i] | 
  447. X            break next
  448. X        }
  449. X        if parser1.errors < parser2.errors then
  450. X        actives[j] := parser1
  451. X        break next
  452. X    }
  453. X    put(new_actives, parser1)
  454. X    }
  455. X
  456. X    every put(actives, !new_actives)
  457. X    return &null
  458. X
  459. Xend
  460. X$$endif                # AUTO_PRUNE
  461. SHAR_EOF
  462. chmod 0444 iiglrpar.lib || echo "restore of iiglrpar.lib fails"
  463. sed 's/^X//' << 'SHAR_EOF' > sample.ibp &&
  464. X#
  465. X# Sample Ibpag2 grammar file.  Don't forget to compile me with string
  466. X# invocation enabled under version 9 (icont -f s).
  467. X#
  468. X
  469. X#
  470. X# The code between %{ and %} gets copied directly.  Note the Iconish
  471. X# comment syntax.
  472. X#
  473. X%{
  474. X
  475. X# Note:  If IIDEBUG is defined in the output file, debugging messages
  476. X# about the stacks and actions get displayed.
  477. X#
  478. X$define IIDEBUG 1
  479. X
  480. X%}
  481. X
  482. X#
  483. X# Here we declare the tokens returned by the lexical analyzer.
  484. X# Precedences increase as we go on.  Note how (unlike YACC), tokens
  485. X# are separated by commas.  Note also how UMINUS is used only for its
  486. X# %prec later.
  487. X#
  488. X%token NUMBER
  489. X%left '+', '-'
  490. X%left '*', '/'
  491. X%right UMINUS
  492. X
  493. X%%
  494. X
  495. X#
  496. X# After this point, and up to the next %%, we have the grammar itself.
  497. X# By default, the start symbol is the left-hand side of the first
  498. X# rule. 
  499. X#
  500. X
  501. Xlines    :    lines, expr, '\n'    { write($2) }
  502. X    |    lines, '\n'
  503. X    |    epsilon     # Note use of epsilon/error tokens.
  504. X    |    error, '\n'        {
  505. X                      write("syntax error; try again:")
  506. X                      # like YACC's yyerrok macro
  507. X                      iierrok
  508. X                    }
  509. X    ;
  510. X
  511. Xexpr    :    expr, '+', expr    { return $1 + $3 }
  512. X    |    expr, '-', expr    { return $1 - $3 }
  513. X    |    expr, '*', expr    { return $1 * $3 }
  514. X    |    expr, '/', expr    { return $1 / $3 }
  515. X    |    '(', expr, ')'    { return $2 }
  516. X    |    '-', expr %prec UMINUS    { return -$2 }
  517. X    |    NUMBER        { return $1 }
  518. X    ;
  519. X
  520. X%%
  521. X
  522. X#
  523. X# From here on, code gets copied directly to the output file.  We are
  524. X# no longer in the grammar proper.
  525. X#
  526. X
  527. X#
  528. X# The lexical analyzer must be called iilex, with the module name
  529. X# appended (if there is one).  It must take one argument, infile (an
  530. X# input stream).  It must be a generator, and fail on EOF (not return
  531. X# something <= 0, as is the case for YACC + Lex).  Iilval holds the
  532. X# literal string value of the token just suspended by iilex().
  533. X#
  534. Xprocedure iilex(infile)
  535. X
  536. X    local nextchar, c, num
  537. X    initial {
  538. X    # Here's where you'd initialize any %{ globals %} declared
  539. X    # above.
  540. X    }
  541. X
  542. X    nextchar := create !(!infile || "\n" || "\n")
  543. X
  544. X    c := @nextchar | fail
  545. X    repeat {
  546. X    if any(&digits, c) then {
  547. X        if not (\num ||:= c) then
  548. X        num := c
  549. X    } else {
  550. X        if iilval := \num then {
  551. X        suspend NUMBER
  552. X        num := &null
  553. X        }
  554. X        if any('+-*/()\n', c) then {
  555. X        iilval := c
  556. X        suspend ord(c)
  557. X        } else {
  558. X        if not any(' \t', c) then {
  559. X            # deliberate error - will be handled later
  560. X            suspend &null
  561. X        }
  562. X        }
  563. X    }
  564. X    c := @nextchar | break
  565. X    }
  566. X    if iilval := \num then {
  567. X    return NUMBER
  568. X    num := &null
  569. X    }
  570. X
  571. Xend
  572. X
  573. Xprocedure main()
  574. X    return iiparse(&input, 1)
  575. Xend
  576. SHAR_EOF
  577. chmod 0444 sample.ibp || echo "restore of sample.ibp fails"
  578. sed 's/^X//' << 'SHAR_EOF' > beta2ref.ibp &&
  579. X#
  580. X# Ibpag2 source file for OT betacode-to-English converter.
  581. X#
  582. X# "Betacode" is the name used for the markers that the Thesaurus
  583. X# Linguae Graecae uses to segment texts into works, books, chapters,
  584. X# verses, etc.  The Michigan-Claremont scan of the Hebrew OT (BHS)
  585. X# uses a subset of the betacode "language."  This file contains a
  586. X# parser for that language that converts it into human readable form.
  587. X#
  588. X# Reads the standard input.  Sends the original text, with betacode
  589. X# markers converted to human-readable form, to the standard output.
  590. X#
  591. X
  592. X%{
  593. X
  594. X# These need to be global, because all of the actions modify them.
  595. X# Remember that the default scope for a variable used in an action is
  596. X# that action.
  597. X#
  598. Xglobal betavals, blev
  599. X
  600. X%}
  601. X
  602. X%token INTVAL, STRVAL, LINE
  603. X
  604. X%%
  605. X
  606. Xbetalines    : betalines, betaline
  607. X        | epsilon
  608. X        ;
  609. X
  610. Xbetaline    : '~', cvalue, xvalue, yvalue, '\n'
  611. X                    { if integer(betavals[2]) then {
  612. X                          write(betavals[1], " ",
  613. X                            betavals[2], ":",
  614. X                            betavals[3])
  615. X                      }
  616. X                      blev := 4 # global
  617. X                    }
  618. X        | LINE, '\n'        { write($1) }
  619. X        ;
  620. X
  621. Xcvalue        : 'a', value, 'b', value, 'c', value
  622. X                    { betavals[blev := 1] := $6 }
  623. X        | 'c', value        { betavals[blev := 1] := $2 }
  624. X        | epsilon
  625. X        ;
  626. X
  627. Xxvalue        : 'x', value        { betavals[blev := 2] := $2 }
  628. X        | 'x'            { if integer(betavals[2])
  629. X                      then betavals[blev := 2] +:= 1
  630. X                      else betavals[blev := 2]  := 1
  631. X                    }
  632. X        | epsilon        { if blev < 2 then
  633. X                          betavals[2] := 1
  634. X                    }
  635. X        ;
  636. X
  637. Xyvalue        : 'y', value        { betavals[blev := 3] := $2 }
  638. X        | 'y'            { betavals[blev := 3] +:= 1 }
  639. X        | epsilon        { if blev < 3 then
  640. X                          betavals[3] := 1
  641. X                    }
  642. X        ;
  643. X
  644. Xvalue        : INTVAL        { return $1 }
  645. X        | STRVAL        { return $1 }
  646. X        ;
  647. X
  648. X
  649. X%%
  650. X
  651. X
  652. Xprocedure iilex(infile)
  653. X
  654. X    local line
  655. X    # betavals is global
  656. X    initial betavals := ["", 0, 0]
  657. X
  658. X    while line := read(infile) do {
  659. X    line ? {
  660. X        if ="~" then {
  661. X        suspend ord("~")
  662. X        until pos(0) do {
  663. X            case move(1) of {
  664. X            "a"     : suspend ord("a")
  665. X            "b"     : suspend ord("b")
  666. X            "c"     : suspend ord("c")
  667. X            "x"     : suspend ord("x")
  668. X            "y"     : suspend ord("y")
  669. X            default : stop("betacode error:  ", line)
  670. X            }
  671. X            if ="\"" then {
  672. X            iilval := tab(find("\""))
  673. X            suspend STRVAL
  674. X            move(1)
  675. X            } else {
  676. X            if iilval := integer(tab(many(&digits)))
  677. X            then suspend INTVAL
  678. X            }
  679. X        }
  680. X        suspend ord("\n")
  681. X        }
  682. X        else {
  683. X        iilval := line
  684. X        suspend LINE
  685. X        suspend ord("\n")
  686. X        }
  687. X    }
  688. X    }
  689. X
  690. Xend
  691. X
  692. X
  693. Xprocedure main()
  694. X    return iiparse(&input)
  695. Xend
  696. SHAR_EOF
  697. chmod 0644 beta2ref.ibp || echo "restore of beta2ref.ibp fails"
  698. sed 's/^X//' << 'SHAR_EOF' > iacc.ibp &&
  699. X############################################################################
  700. X#
  701. X#    Name:     iacc.ibp
  702. X#
  703. X#    Title:     YACC-like front-end for Ibpag2 (experimental)
  704. X#
  705. X#    Author:     Richard L. Goerwitz
  706. X#
  707. X#    $Revision: 1.7 $
  708. X#
  709. X############################################################################
  710. X#
  711. X#  Summary:
  712. X#
  713. X#      Iacc is a YACC-like Ibpag2 preprocessor (very experimental).
  714. X#  Iacc simply reads &input (assumed to be a YACC file, but with Icon
  715. X#  code in the action fields), and writes an Ibpag2 file to &output.
  716. X#
  717. X############################################################################
  718. X#
  719. X#  Installation:
  720. X#
  721. X#      This file is not an Icon file, but rather an Ibpag2 file.  You
  722. X#  must have Ibpag2 installed in order to run it.  To create the iacc
  723. X#  executable, first create iacc.icn by typing "ibpag2 -f iacc.ibp -o
  724. X#  iacc.icn," then compile iacc.icn as you would any other Icon file
  725. X#  to create iacc (or on systems without direct execution, iacc.icx).
  726. X#  Put more simply, iacc.ibp not only outputs Ibpag2 files, but is
  727. X#  itself generated using Ibpag2 + icon{t,c}.  Note that when you com-
  728. X#  pile iacc.icn under Icon version 9.0 or better you must enable
  729. X#  string invocation (icont -f s).
  730. X#
  731. X############################################################################
  732. X#
  733. X#  Implementation notes:
  734. X#
  735. X#      Iacc uses an YACC grammar that is actually LR(2), and not
  736. X#  LR(1), as Ipbag2 would normally require in standard mode.  Iacc
  737. X#  obtains the additional token lookahead via the lexical analyzer.
  738. X#  The place it uses that lookahead is when it sees an identifier.  If
  739. X#  the next token is a colon, then it is the LHS of a rule (C_IDENT
  740. X#  below); otherwise it's an IDENT in the RHS of some rule.  Crafting
  741. X#  the lexical analyzer in this fashion makes semicolons totally
  742. X#  superfluous (good riddance!), but it makes it necessary for the
  743. X#  lexical analyzer to suspend some dummy tokens whose only purpose is
  744. X#  to make sure that it doesn't eat up C or Icon action code while
  745. X#  trying to satisfy the grammar's two-token lookahead requirements
  746. X#  (see how RCURL and '}' are used below in the cdef and act
  747. X#  productions).
  748. X#
  749. X#      Iacc does its work by making six basic changes to the input
  750. X#  stream: 1) puts commas between tokens and symbols in rules, 2)
  751. X#  removes superfluous union and type declarations/tags, 3) inserts
  752. X#  "epsilon" into the RHS of empty rules, 4) turns "$$ = x" into
  753. X#  "return x", 5) rewrites rules so that all actions appear at the end
  754. X#  of a production, and 6) strips all comments.
  755. X#
  756. X#      Although Iacc is really meant for grammars with Icon action
  757. X#  code, Iacc can, in fact, accept straight YACC files, with C action
  758. X#  code.  There isn't much point to using it this way, though, since
  759. X#  its output is not meant to be human readable.  Rather, it is to be
  760. X#  passed directly to Ibpag2 for processing.  Iacc is simply a YACCish
  761. X#  front end.  Its output can be piped directly to Ibpag2 in most
  762. X#  cases:  iacc < infile.iac | ibpag2 > infile.icn.
  763. X#
  764. X############################################################################
  765. X#
  766. X#  Links: longstr, strings
  767. X#  See also: ibpag2
  768. X#
  769. X############################################################################
  770. X
  771. X%{
  772. X
  773. Xlink strings, longstr
  774. Xglobal newrules, lval, symbol_no
  775. X
  776. X%}
  777. X
  778. X# basic entities
  779. X%token C_IDENT, IDENT    # identifiers and literals
  780. X%token NUMBER            # [0-9]+
  781. X
  782. X# reserved words:  %type -> TYPE, %left -> LEFT, etc.
  783. X%token LEFT, RIGHT, NONASSOC, TOKEN, PREC, TYPE, START, UNION
  784. X
  785. X# miscellaneous
  786. X%token MARK   # %%
  787. X%token LCURL  # %{
  788. X%token RCURL  # dummy token used to start processing of C code
  789. X
  790. X%start yaccf
  791. X
  792. X%%
  793. X
  794. Xyaccf    : front, back
  795. Xfront    : defs, MARK        { write(arg2) }
  796. Xback    : rules, tail        {
  797. X                  every write(!\newrules)
  798. X                  if write(\arg2) then
  799. X                      every write(!&input)
  800. X                }
  801. Xtail    : epsilon        { return &null }
  802. X    | MARK            { return arg1 }
  803. X
  804. Xdefs    : epsilon
  805. X    | defs, def        { write(\arg2) }
  806. X    | defs, cdef        { write(\arg2) }
  807. X
  808. Xdef    : START, IDENT        { return arg1 || " " || arg2 }
  809. X    | rword, tag, nlist    {
  810. X                  if arg1 == "%type"
  811. X                  then return &null
  812. X                  else return arg1 || " " || arg3
  813. X                }
  814. Xcdef    : stuff, RCURL, RCURL    { return arg1 }
  815. Xstuff    : UNION            { get_icon_code("%}"); return &null }
  816. X    | LCURL            { return "%{ " || get_icon_code("%}") }
  817. X
  818. Xrword    : TOKEN    | LEFT | RIGHT | NONASSOC | TYPE
  819. X
  820. Xtag    : epsilon        { return &null }
  821. X    | '<', IDENT, '>'    { return "<" || arg2 || ">" }
  822. X
  823. Xnlist    : nmno            { return arg1 }
  824. X    | nlist, nmno        { return arg1 || ", " || arg2 }
  825. X    | nlist, ',', nmno    { return arg1 || ", " || arg3 }
  826. X
  827. Xnmno    : IDENT            { return arg1 }
  828. X    | IDENT, NUMBER        { return arg1 }
  829. X    
  830. Xrules    : LHS, ':', RHS        { write(arg1, "\t: ", arg3) }
  831. X    | rules, rule        { write(arg2) }
  832. X
  833. XRHS    : rbody, prec        { return arg1 || " " || arg2 }
  834. X
  835. Xrule    : LHS, '|', RHS        { return "\t| " || arg3 }
  836. X    | LHS, ':', RHS        { return arg1 || "\t: " || arg3 }
  837. X
  838. XLHS    : C_IDENT        { symbol_no := 0 ; return arg1 }
  839. X    | epsilon        { symbol_no := 0 }
  840. X
  841. Xrbody    : IDENT            { symbol_no +:= 1; return arg1 }
  842. X    | act            { return "epsilon " || arg1 }
  843. X    | middle, IDENT        { return arg1 || ", " || arg2 }
  844. X    | middle, act        { return arg1 || " "  || arg2 }
  845. X    | middle, ',', IDENT    { return arg1 || ", " || arg3 }
  846. X    | epsilon        { return "epsilon" }
  847. X
  848. Xmiddle    : IDENT            { symbol_no +:= 1; return arg1 }
  849. X    | act            { symbol_no +:= 1; return arg1 }
  850. X    | middle, IDENT        { symbol_no +:= 1; return arg1 || ", "||arg2 }
  851. X    | middle, ',', IDENT    { symbol_no +:= 1; return arg1 || ", "||arg3 }
  852. X    | middle, act        {
  853. X                  local i, l1, l2
  854. X                  static actno
  855. X                  initial { actno := 0; newrules := [] }
  856. X                  actno +:= 1
  857. X                  l1 := []; l2 := []
  858. X                  every i := 1 to symbol_no do {
  859. X                      every put(l1, ("arg"|"$") || i)
  860. X                      if symbol_no-i = 0 then i := "0"
  861. X                      else i := "-" || symbol_no - i
  862. X                      every put(l2, ("$"|"$") || i)
  863. X                  }
  864. X                  put(newrules, "ACT_"|| actno ||
  865. X                    "\t: epsilon "|| mapargs(arg2, l1, l2))
  866. X                  symbol_no +:= 1
  867. X                  return arg1 || ", " || "ACT_" || actno
  868. X                }
  869. X
  870. Xact    : '{', cstuff, '}', '}'    { return "{" || arg2 }
  871. Xcstuff    : epsilon        { return get_icon_code("}") }
  872. X
  873. Xprec    : epsilon        { return "" }
  874. X    | PREC, IDENT        { return arg1 || arg2 }
  875. X    | PREC, IDENT, act    { return arg1 || arg2 || arg3 }
  876. X
  877. X
  878. X%%
  879. X
  880. X
  881. Xprocedure iilex()
  882. X
  883. X    local t
  884. X    static last_token, last_lval, colon
  885. X    initial colon := ord(":")
  886. X
  887. X    every t := next_token() do {
  888. X    iilval := last_lval
  889. X    if \last_token then {
  890. X        if t = colon then {
  891. X        if last_token = IDENT
  892. X        then suspend C_IDENT
  893. X        else suspend last_token
  894. X        } else
  895. X        suspend last_token
  896. X    }
  897. X    last_token := t
  898. X    last_lval := lval
  899. X    }
  900. X    iilval := last_lval
  901. X    suspend \last_token
  902. X
  903. Xend
  904. X
  905. X
  906. Xprocedure next_token()
  907. X
  908. X    local reserveds, UNreserveds, c, idchars, marks
  909. X
  910. X    reserveds := ["break","by","case","create","default","do",
  911. X          "else","end","every","fail","global","if",
  912. X          "initial","invocable","link","local","next",
  913. X          "not","of","procedure","record","repeat",
  914. X          "return","static","suspend","then","to","until",
  915. X          "while"]
  916. X
  917. X    UNreserveds := ["break_","by_","case_","create_","default_","do_",
  918. X            "else_","end_","every_","fail_","global_","if_",
  919. X            "initial_","invocable_","link_","local_","next_",
  920. X            "not_","of_","procedure_","record_","repeat_",
  921. X            "return_","static_","suspend_","then_","to_",
  922. X            "until_","while_"]
  923. X
  924. X    idchars := &letters ++ '._'
  925. X    marks := 0
  926. X
  927. X    c := reads()
  928. X    repeat {
  929. X    lval := &null
  930. X    case c of {
  931. X        "#" : { do_icon_comment(); c := reads() | break }
  932. X        "<" : { suspend ord(c); c := reads() | break }
  933. X        ">" : { suspend ord(c); c := reads() | break }
  934. X        ":" : { suspend ord(c); c := reads() | break }
  935. X        "|" : { suspend ord(c); c := reads() | break }
  936. X        "," : { suspend ord(c); c := reads() | break }
  937. X        "{" : { suspend ord(c | "}" | "}"); c := reads() }
  938. X        "/" : {
  939. X        reads() == "*" | stop("unknown YACC operator, \"/\"")
  940. X        do_c_comment()
  941. X        c := reads() | break
  942. X        }
  943. X        "'" : {
  944. X        lval := "'"
  945. X        while lval ||:= (c := reads()) do {
  946. X            if c == "\\"
  947. X            then lval ||:= reads()
  948. X            else if c == "'" then {
  949. X            suspend IDENT
  950. X            break
  951. X            }
  952. X        }
  953. X        c := reads() | break
  954. X        }
  955. X        "%" : {
  956. X        lval := "%"
  957. X        while any(&letters, c := reads()) do 
  958. X            lval ||:= c
  959. X        if *lval = 1 then {
  960. X            if c == "%" then {
  961. X            lval := "%%"
  962. X            suspend MARK
  963. X            if (marks +:= 1) > 1 then
  964. X                fail
  965. X            } else {
  966. X            if c == "{" then {
  967. X                lval := "%{"
  968. X                suspend LCURL | RCURL | RCURL
  969. X            }
  970. X            else stop("malformed %declaration")
  971. X            }
  972. X            c := reads() | break
  973. X        } else {
  974. X            case lval of {
  975. X            "%prec"     : suspend PREC
  976. X            "%left"     : suspend LEFT
  977. X            "%token"    : suspend TOKEN
  978. X            "%right"    : suspend RIGHT
  979. X            "%type"     : suspend TYPE
  980. X            "%start"    : suspend START
  981. X            "%union"    : suspend UNION | RCURL | RCURL
  982. X            "%nonassoc" : suspend NONASSOC
  983. X            default    : stop("unknown % code in def section")
  984. X            }
  985. X        }
  986. X        }
  987. X        default : {
  988. X        if any(&digits, c) then {
  989. X            lval := c
  990. X            while any(&digits, c := reads()) do
  991. X            lval ||:= c
  992. X            suspend NUMBER
  993. X        }    
  994. X        else {
  995. X            if any(idchars, c) then {
  996. X            lval := c
  997. X            while any(&digits ++ idchars, c := reads()) do
  998. X                lval ||:= c
  999. X            lval := mapargs(lval, reserveds, UNreserveds)
  1000. X            suspend IDENT
  1001. X            }
  1002. X            else {
  1003. X            # whitespace
  1004. X            c := reads() | break
  1005. X            }
  1006. X        }
  1007. X        }
  1008. X    }
  1009. X    }
  1010. X
  1011. X
  1012. Xend
  1013. X
  1014. X
  1015. Xprocedure get_icon_code(endmark, comment)
  1016. X
  1017. X    local yaccwords, ibpagwords, count, c, c2, s
  1018. X
  1019. X    yaccwords := ["YYDEBUG", "YYACCEPT", "YYERROR", "yyclearin", "yyerrok"]
  1020. X    ibpagwords := ["IIDEBUG", "IIACCEPT", "IIERROR", "iiclearin", "iierrok"]
  1021. X
  1022. X    s := ""
  1023. X    count := 1
  1024. X    c := reads()
  1025. X
  1026. X    repeat {
  1027. X    case c of {
  1028. X        "\""    :  s ||:= c || do_string()
  1029. X        "'"     :  s ||:= c || do_charlit()
  1030. X        "$"     :  {
  1031. X        c2 := reads() | break
  1032. X        if c2 == "$" then {
  1033. X            until (c := reads()) == "="
  1034. X            s ||:= "return "
  1035. X        } else {
  1036. X            s ||:= c
  1037. X            c := c2
  1038. X            next
  1039. X        }
  1040. X        }
  1041. X        "#"     :  {
  1042. X        if s[-1] == "\n"
  1043. X        then s[-1] := ""
  1044. X        do_icon_comment()
  1045. X        }
  1046. X        "/" : {
  1047. X        c := reads() | break
  1048. X        if c == "*" then
  1049. X            do_c_comment()
  1050. X        else {
  1051. X            s ||:= c
  1052. X            next
  1053. X        }
  1054. X        }
  1055. X        "{"     :  {
  1056. X        s ||:= c
  1057. X        if endmark == "}" then
  1058. X            count +:= 1
  1059. X        }
  1060. X        "}"     :  {
  1061. X        s ||:= c
  1062. X        if endmark == "}" then {
  1063. X            count -:= 1
  1064. X            count = 0 & (return mapargs(s, yaccwords, ibpagwords))
  1065. X        }
  1066. X        }
  1067. X        "%"     :  {
  1068. X        s ||:= c
  1069. X        if endmark == "%}" then {
  1070. X            if (c := reads()) == "}"
  1071. X            then return mapargs(s || c, yaccwords, ibpagwords)
  1072. X            else next
  1073. X        }
  1074. X        }
  1075. X        default : s ||:= c
  1076. X    }
  1077. X    c := reads() | break
  1078. X    }
  1079. X
  1080. X    # if there is no endmark, just go to EOF
  1081. X    if \endmark
  1082. X    then stop("input file has mis-braced { code }")
  1083. X    else return mapargs(s, yaccwords, ibpagwords)
  1084. X
  1085. Xend
  1086. X
  1087. X
  1088. Xprocedure do_string()
  1089. X
  1090. X    local c, s
  1091. X
  1092. X    s := ""
  1093. X    while c := reads() do {
  1094. X    case c of {
  1095. X        "\\"    : s ||:= c || reads()
  1096. X        "\""    : return s || c || reads()
  1097. X        default : s ||:= c
  1098. X    }
  1099. X    }
  1100. X
  1101. X    stop("malformed string literal")
  1102. X
  1103. Xend
  1104. X
  1105. X
  1106. Xprocedure do_charlit()
  1107. X
  1108. X    local c, s
  1109. X
  1110. X    s := ""
  1111. X    while c := reads() do {
  1112. X    case c of {
  1113. X        "\\"    : s ||:= c || reads()
  1114. X        "'"     : return s || c || reads()
  1115. X        default : s ||:= c
  1116. X    }
  1117. X    }
  1118. X
  1119. X    stop("malformed character literal")
  1120. X
  1121. Xend
  1122. X
  1123. X
  1124. Xprocedure do_c_comment()
  1125. X
  1126. X    local c, s
  1127. X
  1128. X    s := c := reads() |
  1129. X    stop("malformed C-style /* comment */")
  1130. X
  1131. X    repeat {
  1132. X    if c == "*" then {
  1133. X        s ||:= (c := reads() | break)
  1134. X        if c == "/" then
  1135. X        return s
  1136. X    }
  1137. X    else s ||:= (c := reads() | break)
  1138. X    }
  1139. X
  1140. X    return s            # EOF okay
  1141. X
  1142. Xend
  1143. X
  1144. X
  1145. Xprocedure do_icon_comment()
  1146. X
  1147. X    local c, s
  1148. X
  1149. X    s := ""
  1150. X    while c := reads() do {
  1151. X    case c of {
  1152. X        "\\"    : s ||:= c || (reads() | break)
  1153. X        "\n"    : return s
  1154. X        default : s ||:= c
  1155. X    }
  1156. X    }
  1157. X
  1158. X    return s            # EOF okay
  1159. X
  1160. Xend
  1161. X
  1162. X
  1163. Xprocedure mapargs(s, l1, l2)
  1164. X
  1165. X    local i, s2
  1166. X    static cs, tbl, last_l1, last_l2
  1167. X
  1168. X    if /l1 | *l1 = 0 then return s
  1169. X
  1170. X    if not (last_l1 === l1, last_l2 === l2) then {
  1171. X    cs := ''
  1172. X    every cs ++:= (!l1)[1]
  1173. X    tbl := table()
  1174. X    every i := 1 to *l1 do
  1175. X        insert(tbl, l1[i], (\l2)[i] | "")
  1176. X    }
  1177. X
  1178. X    s2 := ""
  1179. X    s ? {
  1180. X    while s2 ||:= tab(upto(cs)) do {
  1181. X        (s2 <- (s2 || tbl[tab(longstr(l1))]),
  1182. X            not any(&letters++&digits++'_')) |
  1183. X            (s2 ||:= move(1))
  1184. X    }
  1185. X    s2 ||:= tab(0)
  1186. X    }
  1187. X
  1188. X    return s2
  1189. X
  1190. Xend
  1191. X
  1192. X
  1193. Xprocedure main()
  1194. X    iiparse()
  1195. Xend
  1196. SHAR_EOF
  1197. chmod 0444 iacc.ibp || echo "restore of iacc.ibp fails"
  1198. sed 's/^X//' << 'SHAR_EOF' > Makefile.dist &&
  1199. X##########################################################################
  1200. X#
  1201. X   PROGNAME = ibpag2
  1202. X#
  1203. X##########################################################################
  1204. X#
  1205. X#  User-modifiable section.  Read carefully!  You will almost
  1206. X#  certainly have to change some settings here.
  1207. X#
  1208. X
  1209. X#
  1210. X# Destination directory for binaries files.  Owner and group for
  1211. X# public executables.  Leave the trailing slash off of directory
  1212. X# names.
  1213. X#
  1214. XOWNER = richard # root
  1215. XGROUP = group   # root
  1216. XDESTDIR = /usr/local/bin
  1217. X# Put this path into your LPATH variable (on which, see the Icon
  1218. X# documentation).  Make sure that the directory exists.
  1219. XLIBDIR = /usr/lib/icon/data
  1220. X
  1221. X#
  1222. X# Name of your icon compiler and compiler flags.
  1223. X#
  1224. XICONC = /usr/icon/v9/bin/icont
  1225. XIFLAGS = -u #-Sc 400 -Sg 400 -Si 2000 -Sn 4000 -SF 40
  1226. X
  1227. XSHELL = /bin/sh
  1228. XSHAR = /usr/bin/shar
  1229. XCOMPRESS = /usr/bin/compress
  1230. X# COMPRESS = /usr/local/bin/gzip
  1231. X
  1232. X###########################################################################
  1233. X#
  1234. X#  Don't change anything below this line unless you're really sure of
  1235. X#  what you're doing.
  1236. X#
  1237. X
  1238. XAUX = slshupto.icn rewrap.icn outbits.icn sortff.icn itokens.icn
  1239. XSRC = $(PROGNAME).icn $(AUX) slrtbls.icn slritems.icn follow.icn \
  1240. X    ibutil.icn iohno.icn ibreader.icn ibwriter.icn shrnktbl.icn \
  1241. X    version.icn
  1242. XPARSER = iiparse.lib
  1243. XGLRPARSER = iiglrpar.lib
  1244. XSHARFILES = $(SRC) $(PARSER) $(GLRPARSER) sample.ibp beta2ref.ibp \
  1245. SHAR_EOF
  1246. echo "End of part 6, continue with part 7"
  1247. echo "7" > s2_seq_.tmp
  1248. exit 0
  1249. -- 
  1250.  
  1251.    -Richard L. Goerwitz              goer%midway@uchicago.bitnet
  1252.    goer@midway.uchicago.edu          rutgers!oddjob!ellis!goer
  1253.