xread.red 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. module xread; % Routines for parsing RLISP input.
  2. % Author: Anthony C. Hearn.
  3. % Copyright (c) 1991 The RAND Corporation. All rights reserved.
  4. fluid '(!*blockp !*eoldelimp !*reduce4); % !*ignoreeol
  5. global '(cursym!* nxtsym!*);
  6. % The conversion of an RLISP expression to LISP prefix form is carried
  7. % out by the function XREAD. This function initiates the scanning
  8. % process, and then calls the auxiliary function XREAD1 to perform the
  9. % actual parsing. Both XREAD and XREAD1 are used by many functions
  10. % whenever an expression must be read;
  11. flag ('(end !*colon!* !*semicol!*),'delim);
  12. symbolic procedure chknewnam u;
  13. % Check to see if U has a newnam, and return it else return U.
  14. begin scalar x;
  15. return if null(x := get(u,'newnam)) or x eq u then u
  16. else if idp x then chknewnam x
  17. else x
  18. end;
  19. symbolic procedure mkvar(u,v); u;
  20. symbolic procedure remcomma u;
  21. if eqcar(u,'!*comma!*) then cdr u else list u;
  22. symbolic procedure eolcheck;
  23. if null !*eoldelimp then nil
  24. else begin
  25. a: if nxtsym!* eq !$eol!$
  26. then progn(nxtsym!* := (if cursym!* eq 'end then '!;
  27. else token()),
  28. go to a)
  29. end;
  30. symbolic procedure xread1 u;
  31. begin scalar v,w,x,y,z,z1,z2;
  32. % This is the basic function for parsing RLISP input, once
  33. % tokens have been read by TOKEN and SCAN. Its one argument
  34. % U can take a number of values:
  35. % FOR: Parsing of FOR statements
  36. % GROUP: Parsing of group statements after keyword <<
  37. % LAMBDA: Parsing of lambda expressions after keyword lambda
  38. % NIL: Parsing of expressions which can have a comma at
  39. % the end for example.
  40. % PROC: Parsing of procedures after keyword PROCEDURE
  41. % T: Default case with standard parsing.
  42. % Also, if U is flagged STRUCT, it is assumed that the arguments
  43. % are lists of lists, and so commas are removed. At present,
  44. % only MAT is tagged in this manner.
  45. % The local variables are used as follows:
  46. % v: expression being built
  47. % w: prefix operator stack
  48. % x: infix operator stack
  49. % y: infix value or stat property
  50. % z: current symbol
  51. % z1: next symbol
  52. % z2: temporary storage;
  53. a: z := cursym!*;
  54. a1: if null idp z then nil
  55. else if z eq '!*lpar!* then go to lparen
  56. else if z eq '!*rpar!* then go to rparen
  57. else if y := get(z,'infix) then go to infx
  58. % The next line now commented out was intended to allow a STAT
  59. % to be used as a label. However, it prevents the definition of
  60. % a diphthong whose first character is a colon.
  61. % else if nxtsym!* eq '!: then nil
  62. else if flagp(z,'delim) then go to delimit
  63. else if y := get(z,'stat) then go to stat
  64. else if null !*reduce4 and flagp(z,'type)
  65. then progn(w := lispapply('decstat,nil) . w, go to a);
  66. a2: y := nil;
  67. a3: w := z . w;
  68. % allow for implicit * after a number.
  69. if toknump z
  70. and null(z1 eq !$eol!$)
  71. and idp (z1 := chknewnam nxtsym!*)
  72. and null flagp(z1,'delim)
  73. and null(get(z1,'switch!*) and null(z1 eq '!())
  74. and null get(z1,'infix)
  75. and null (!*eoldelimp and z1 eq !$eol!$)
  76. then progn(cursym!* := 'times, go to a)
  77. else if u eq 'proc and length w > 2
  78. then symerr("Syntax error in procedure header",nil);
  79. next: z := scan();
  80. go to a1;
  81. lparen:
  82. eolcheck();
  83. y := nil;
  84. if scan() eq '!*rpar!* then go to lp1 % no args
  85. else if flagpcar(w,'struct) then z := xread1 car w
  86. else z := xread1 'paren;
  87. if flagp(u,'struct) then progn(z := remcomma z, go to a3)
  88. else if null eqcar(z,'!*comma!*) then go to a3
  89. else if null w % then go to a3
  90. then (if u eq 'lambda then go to a3
  91. else symerr("Improper delimiter",nil))
  92. else w := (car w . cdr z) . cdr w;
  93. go to next;
  94. lp1: if w then w := list car w . cdr w; % Function of no args.
  95. go to next;
  96. rparen:
  97. if null u or u eq 'group
  98. or u eq 'proc % and null !*reduce4
  99. then symerr("Too many right parentheses",nil)
  100. else go to end1;
  101. infx: eolcheck();
  102. if z eq '!*comma!* or null atom (z1 := scan())
  103. or toknump z1 then go to in1
  104. else if z1 eq '!*rpar!* % Infix operator used as variable.
  105. or z1 eq '!*comma!*
  106. or flagp(z1,'delim)
  107. then go to in2
  108. else if z1 eq '!*lpar!* % Infix operator in prefix position.
  109. and null eolcheck() % Side effect important
  110. and null atom(z1 := xread 'paren)
  111. and car z1 eq '!*comma!*
  112. and (z := z . cdr z1)
  113. then go to a1;
  114. in1: if w then go to unwind
  115. else if null(z := get(z,'unary))
  116. then symerr("Redundant operator",nil);
  117. v := '!*!*un!*!* . v;
  118. go to pr1;
  119. % in2: if y then if !*ignoreeol then y := nil
  120. % else symerr("Redundant operator",nil);
  121. in2: if y then y := nil;
  122. w := z . w;
  123. in3: z := z1;
  124. go to a1;
  125. unwind:
  126. % Null w implies a delimiter was found, say, after a comma.
  127. if null w then symerr("Improper delimiter",nil);
  128. z2 := mkvar(car w,z);
  129. un1: w:= cdr w;
  130. if null w then go to un2
  131. % Next line used to be toknump car w, but this test catches more
  132. % else if null idp car w and null eqcar(car w,'lambda)
  133. else if atom car w and null idp car w
  134. % and null eqcar(car w,'lambda)
  135. then symerr("Missing operator",nil);
  136. z2 := list(car w,z2);
  137. go to un1;
  138. un2: v:= z2 . v;
  139. preced:
  140. if null x then if y=0 then go to end2 else nil
  141. % else if z eq 'setq then nil
  142. % Makes parsing a + b := c more natural.
  143. else if y<caar x
  144. or (y=caar x
  145. and ((z eq cdar x and null flagp(z,'nary)
  146. and null flagp(z,'right))
  147. or get(cdar x,'alt)))
  148. then go to pr2;
  149. pr1: x:= (y . z) . x;
  150. if null(z eq '!*comma!*) then go to in3
  151. else if cdr x or null u or u memq '(lambda paren)
  152. or flagp(u,'struct)
  153. then go to next
  154. else go to end2;
  155. pr2: %if cdar x eq 'setq then go to assign else;
  156. % Check for NOT used as infix operator.
  157. if eqcar(cadr v,'not) and caar x >= get('member,'infix)
  158. then typerr("NOT","infix operator");
  159. if cadr v eq '!*!*un!*!*
  160. then (if car v eq '!*!*un!*!* then go to pr1
  161. else z2 := list(cdar x,car v))
  162. else z2 := cdar x .
  163. if eqcar(car v,cdar x) and flagp(cdar x,'nary)
  164. then (cadr v . cdar v)
  165. else list(cadr v,car v);
  166. x:= cdr x;
  167. v := z2 . cddr v;
  168. go to preced;
  169. stat: if null(y eq 'endstat) then eolcheck();
  170. if null(flagp(z,'go)
  171. % or (flagp(y,'endstatfn)
  172. or null(u eq 'proc) and (flagp(y,'endstatfn)
  173. or (null delcp nxtsym!* and null (nxtsym!* eq '!,))))
  174. then go to a2;
  175. if z eq 'procedure and !*reduce4
  176. then if w then if cdr w or !*reduce4
  177. then symerr("proc form",nil)
  178. else w := list procstat1 car w
  179. else w := list procstat1 nil
  180. else w := lispapply(y,nil) . w;
  181. y := nil;
  182. go to a;
  183. delimit:
  184. if null(cursym!* eq '!*semicol!*) then eolcheck();
  185. if z eq '!*colon!* and null(u eq 'for)
  186. and (null !*blockp or null w or null atom car w or cdr w)
  187. or flagp(z,'nodel)
  188. and (null u
  189. or u eq 'group
  190. and null(z memq
  191. '(!*rsqbkt!* !*rcbkt!* !*rsqb!*)))
  192. then symerr("Improper delimiter",nil)
  193. else if idp u and (u eq 'paren or flagp(u,'struct))
  194. then symerr("Too few right parentheses",nil);
  195. end1:
  196. if y then symerr("Improper delimiter",nil) % Probably ,).
  197. else if null v and null w and null x then return nil;
  198. y := 0;
  199. go to unwind;
  200. end2: if null cdr v then return car v
  201. else print "Please send hearn@rand.org your program!!";
  202. symerr("Improper delimiter",nil)
  203. end;
  204. %symbolic procedure getels u;
  205. % getel(car u . !*evlis cdr u);
  206. %symbolic procedure !*evlis u;
  207. % mapcar(u,function lispeval);
  208. flag ('(endstat retstat),'endstatfn);
  209. flag ('(else then until),'nodel);
  210. flag ('(begin),'go);
  211. symbolic procedure xread u;
  212. begin
  213. a: scan();
  214. if !*eoldelimp and cursym!* eq '!*semicol!* then go to a;
  215. return xread1 u
  216. end;
  217. symbolic procedure expread; xread t;
  218. flag('(expread xread),'opfn); % To make them operators.
  219. endmodule;
  220. end;