tools.red 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. % Description: This file contains various important functions which are used by all modules
  2. % of the program. Of importance is the lexer, and the functions dealing with
  3. % XML attributes for both OpenMath and MathML as well as the error message
  4. % generator.
  5. %
  6. % Date: 25 March 2000
  7. %
  8. % Author: Luis Alvarez Sobreviela
  9. %
  10. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  11. % Declaration of two switches.
  12. % _mathml_ allows all output to be printed in mathml.
  13. % _both_ allows all output to be printed in mathml and in normal reduce
  14. % output.
  15. load assist;
  16. load matrix;
  17. global '(f dfunctions!* file!*);
  18. %Initialisation of REDUCE switches.
  19. global '(!*mathml);
  20. switch mathml;
  21. global '(!*both);
  22. switch both;
  23. global '(!*web);
  24. switch web;
  25. LISP (FILE!*:=nil);
  26. !*mathml:=nil;
  27. !*both:=nil;
  28. !*web:=nil;
  29. off both;
  30. off mathml;
  31. off web;
  32. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  33. % The following functions are the lexer. When called they return the next %
  34. % mathml token in the input stream. %
  35. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  36. symbolic procedure lex();
  37. begin scalar token,safe_atts;
  38. % princ "Char: ";print char;
  39. token:=nil;
  40. char:=nil;
  41. if atts neq nil then safe_atts:=atts;
  42. atts:=nil;
  43. if ch eq int2id(10) then ch:=readch();
  44. if ch neq !$EOF!$ then <<
  45. if ch=space then while (ch:=readch())=space do
  46. else
  47. if ch='!< then char:=get_token()
  48. else char:=get_content();
  49. if char neq nil then
  50. << count:=count+1;
  51. token:=reverse char;
  52. if notstring char then <<
  53. char:=butes(token); % a token is striped from its attributes.
  54. isvalid(char); % Make sure token is not a string
  55. attributes(char,token)>> % and they are stored by the function attributes
  56. >>
  57. else lex(); >>
  58. end;
  59. % Returns anything until the XML element '>' closing character
  60. symbolic procedure get_token();
  61. begin scalar d;
  62. d:='();
  63. while (ch:=readch()) neq '!> do d:=cons(ch,d);
  64. return cons('!$,d);
  65. end;
  66. % This function reads the elements within XML tags. It will skip and ignore
  67. % unnecessary spaces. However if the element is a string then it will keep
  68. % the spaces.
  69. symbolic procedure get_content();
  70. begin scalar d, d2;
  71. d:='();
  72. while (ch:=readch()) neq '!< AND ch neq !$EOF!$ do <<
  73. if ch neq int2id(10) then
  74. d:=cons(ch,d)
  75. >>;
  76. d2:=delall('! , d);
  77. if d2 eq nil then d:=nil
  78. else
  79. <<if car d2 neq '!" AND car reverse d2 neq '!" then
  80. d:=d2 else return reverse d>>;
  81. if d neq nil then d:=cons('!$,d);
  82. return d;
  83. end;
  84. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  85. % The following fuctions deal with XML attributes. %
  86. % %
  87. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  88. % The following function will search a list of attributes _att_ for the attribute
  89. % named _key_. It is useful for getting the value of a particular attribute from
  90. % a MathML token which contains various attributes
  91. symbolic procedure search_att( att, key);
  92. begin scalar l, stop,d;
  93. l:=nil;
  94. d:=();
  95. stop:=0;
  96. att:= find2(att, key);
  97. if att neq '(stop) then
  98. <<
  99. while (car att='! ) do att:=cdr att;
  100. if (car att = '!=) then
  101. <<
  102. att:=cdr att;
  103. while (car att='! ) do att:=cdr att;
  104. if (car att='!") then
  105. << att:=cdr att;
  106. while (stop=0) do
  107. << d:=cons(car att, d);
  108. att:=cdr att;
  109. if (car att='! ) OR (car att='!$) then stop:=1
  110. >>
  111. >>
  112. else
  113. while (stop=0) do
  114. << d:=cons(car att, d);
  115. att:=cdr att;
  116. if (car att='! ) OR (car att='!$) then stop:=1
  117. >>
  118. >>
  119. else
  120. errorML(compress key,1);
  121. if car d='!" then d:=cdr d;
  122. return reverse d
  123. >>
  124. end;
  125. % _attributes(a,b)_ reads the attributes of a MathML token and
  126. % stores them in global variable atts
  127. symbolic procedure attributes(a,b);
  128. begin scalar l;
  129. l:=length a;
  130. for a:=1:l do b:=cdr b;
  131. while (car b='! ) do b:=cdr b;
  132. if b neq '(!$) then atts:=b;
  133. end;
  134. % butes removes all attributes to a token. Necessary when parsing. The attributes of the
  135. % current character are always stored in atts in case they are necessary.
  136. symbolic procedure butes( str );
  137. begin scalar cha;
  138. cha:=car str;
  139. return if (cha='! OR cha='!$) then <<'(); >>
  140. else cons(car str, butes cdr str);
  141. end;
  142. % This function takes a list of attributes
  143. % and their corresponding values _fatt_ and
  144. % the name of the attribute wanted _fkey_.
  145. % It then returns the value of that attribute.
  146. % eg: find('...., 'type);
  147. symbolic procedure find(fatt, fkey);
  148. begin scalar a;
  149. fkey := explode fkey;
  150. a:=find2(fatt, fkey);
  151. % debug("find a: ",a);
  152. if car a neq '!= then a:=find2(a, fkey);
  153. % debug("find a: ",a);
  154. % debug("",);
  155. a:=delall('!", a);
  156. a:=delall('!=, a);
  157. a:=delall('!$, a);
  158. if a neq '(stop) then
  159. if car reverse a = '!/ then
  160. a:=reverse cdr reverse a; %will remove the !/ character at the end.
  161. if a neq '(stop) then
  162. if fkey = '(d e f i n i t i o n u r l) then return delall('! ,a)
  163. else return compress!* a
  164. else return nil;
  165. end;
  166. symbolic procedure compress!* u;
  167. begin scalar x;
  168. if digit car u then return compress u;
  169. for each j in u do
  170. if j eq '!/ or j eq '!- or j eq '!; or j eq '!.
  171. then x := j . '!! . x
  172. else x := j . x;
  173. return intern compress reversip x
  174. end;
  175. symbolic procedure find2(fatt, fkey);
  176. begin;
  177. return if fkey= '() then if fatt neq nil then cdr fatt else '(stop)
  178. else
  179. find2(member(car fkey, fatt), cdr fkey);
  180. end;
  181. % Given a list of attributes _ats_ and a list of attributes
  182. % of interest _list_ it will return a list containing
  183. % the attribute names and their corresponding attribute values.
  184. symbolic procedure retattributes( ats, list );
  185. begin scalar a;
  186. if list eq nil then nil
  187. else <<
  188. a:=find(ats, car list);
  189. if a neq nil then
  190. return cons(list(car list, a ), retattributes(ats,cdr list))
  191. else return retattributes(ats,cdr list);
  192. >>;
  193. end;
  194. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  195. % The following functions are handy tools. Some of them are very useful %
  196. % Others are modifications of REDUCE functions which were not perfectly %
  197. % suitable for the tasks required by this program %
  198. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  199. % When a token has its attributes stripped off, it looses the !/ character
  200. % at the end. This function restores this character only if the token is valid.
  201. % It is valid if it is part of the functions!* list. If not it doesn't restore
  202. % the !/ character and calls an error
  203. symbolic procedure isvalid(a);
  204. begin;
  205. if IDP compress a neq t then return compress a;
  206. if assoc(compress!* a, functions!*) then return t;
  207. a:=reverse cons('!/, reverse a);
  208. if assoc(compress!* a, functions!*) then <<char:=a; return t>>;
  209. return nil;
  210. end;
  211. % This function checks that a given token or element
  212. % produced by the lexer is not a string.
  213. symbolic procedure notstring(a);
  214. begin scalar a, a2;
  215. a2:=delall('! , a);
  216. if car a2 neq '!" AND car reverse a2 neq '!"
  217. then return t else return nil;
  218. end;
  219. % This function will take a list as argument and return a list where
  220. % only one copy is kept of elements appearing more than once.
  221. symbolic procedure norepeat(args);
  222. begin;
  223. return if args=nil then nil else
  224. if length args=1 then list car args
  225. else append(list car args, norepeat(delall(car args, cdr args)));
  226. end;
  227. % This function will delete all occurences of element x in list l
  228. symbolic procedure delall(x,l);
  229. if l=nil then nil
  230. else if x=car l then delall(x, cdr l)
  231. else append(list car l ,delall(x, cdr l));
  232. % This function takes a list of characters and prints them out together.
  233. % It is like compress but works better when it comes to uniting and
  234. % printing the elements of a list.
  235. symbolic procedure list2string(a);
  236. begin;
  237. if a neq nil then <<princ car a; list2string(cdr a)>>;
  238. end;
  239. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  240. % The following function is in charge of providing the correct error message %
  241. % as well as closing the input/output stream, and exiting the program %
  242. % correctly. %
  243. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  244. symbolic procedure errorML( str, msg );
  245. begin;
  246. terpri();
  247. princ "***** Error in token number ";
  248. princ count;
  249. princ " (<";
  250. princ compress char;
  251. princ ">)";
  252. terpri();
  253. if msg=1 then
  254. << princ "Needed attribute";
  255. princ str;
  256. princ " and none was found.">> else
  257. if msg=2 then
  258. << princ "Missing tag: ";
  259. princ str >> else
  260. if msg=3 then
  261. << princ "Undefined error!" >> else
  262. if msg=4 then
  263. << princ "Numerical constant ";
  264. princ str;
  265. princ " was enclosed between <ci></ci> tags.";
  266. terpri();
  267. princ "Correct syntax: <cn>";
  268. princ str;
  269. princ "</cn>.">> else
  270. if msg=5 then
  271. << princ "All arguments must be sets";
  272. terpri();
  273. princ str;
  274. princ " does not represent a set.">> else
  275. if msg=6 then
  276. << princ "Non-numeric argument in arithmetic.">> else
  277. if msg=7 then
  278. << princ "The degree quantifier is of no use in the sumation";
  279. princ "operator.">> else
  280. if msg=8 then
  281. << princ "The degree quantifier is of no use in the limit";
  282. princ " operator.">> else
  283. if msg=9 then
  284. << princ "The index of sumation has not been specified.";
  285. terpri();
  286. princ "Please use <bvar></bvar> tags to specify an index.">>
  287. else
  288. if msg=10 then
  289. << princ "Upperlimit not specified.">> else
  290. if msg=11 then
  291. << princ "Upper and lower limits have not been specified.">> else
  292. if msg=12 then
  293. << princ "The degree quantifier is of no use in the product";
  294. princ " operator.">> else
  295. if msg=13 then
  296. << princ "The degree quantifier is not allowed in the integral";
  297. princ " operator.">> else
  298. if msg=14 then
  299. << princ "Variable of integration not specified.";
  300. princ "Please use <bvar></bvar> tags to specify variable.">>
  301. else
  302. if msg=15 then
  303. << princ "Incorrect use of <bvar></bvar> tags.";
  304. princ " Correct use:";
  305. terpri();
  306. princ
  307. "<bvar> bound_var </bvar> [<degree> degree </degree>] </bvar>">> else
  308. if msg=16 then
  309. << princ "Symbolic constant ";
  310. princ str;
  311. princ " was enclosed between <cn></cn> tags.";
  312. terpri();
  313. princ "Correct syntax: <ci> ";
  314. princ str;
  315. princ " </ci>";
  316. terpri();
  317. princ "or <cn type=""constant""> </cn>";
  318. princ "if using constants &ImaginaryI;, &ii;, &ExponentialE;, &gamma;, &ee; or &pi;."
  319. >> else
  320. if msg=17 then
  321. << princ "Unknown tag: <";
  322. princ str;princ ">.";
  323. terpri();
  324. princ "Token not allowed within <apply></apply> tags.";
  325. terpri();
  326. princ "Might be: <"; princ str; princ "/>.">> else
  327. if msg=18 then
  328. << princ "Unknown tag: <";
  329. princ str;princ ">.";
  330. terpri();
  331. princ "Not allowed within <reln></reln> tags.">> else
  332. if msg=19 then
  333. << princ "Undefined error!";
  334. princ " Token "; princ sub1 count;
  335. princ " is probably mispelled";
  336. terpri();
  337. princ "or unknown, ";
  338. princ "or the </math> tag is missing">> else
  339. if msg=20 then
  340. << princ "Function ";
  341. princ str;
  342. princ "()";
  343. princ " was not enclosed in <ci></ci> tags.";
  344. terpri();
  345. princ "Correct syntax: <fn><ci>";
  346. princ str;
  347. princ "</ci></fn>.">> else
  348. if msg=21 then
  349. << princ "Error, division by 0">> else
  350. if msg=22 then
  351. << princ "<tendsto/> should contain a type attribute";
  352. terpri();
  353. princ "example: <tendsto type=""above""/>";>>;
  354. terpri();
  355. if FILE!*=t then close rds !*f!*;
  356. FILE!*:=nil;
  357. rederr("");
  358. rederr("");
  359. terpri();
  360. end;
  361. % This function transforms a list representing a list of matrix columns
  362. % to a list representing a list of matrix rows
  363. % Very important in order to deal with OpenMath's way of
  364. % representing Matrices which can be both with columns
  365. % or rows.
  366. symbolic procedure cols2rows(l);
  367. begin scalar len;
  368. % return l;
  369. len := length car l;
  370. return reverse cols2rows2(l, len);
  371. end;
  372. symbolic procedure cols2rows2(l, s);
  373. begin;
  374. if s neq 0 then return cons(ithListElem(l, s), cols2rows2(l, s-1));
  375. end;
  376. % This function is given a list of lists (ie a matrix) and an index i.
  377. % It then returns a list containing the ith element of the lists in the list lst
  378. % for example: listelem('((1 2)(3 4)(5 6)), 2) --> (2 4 6)
  379. symbolic procedure ithListElem(lst, i);
  380. begin;
  381. if lst neq nil then return cons(nth(car lst, i), ithlistelem (cdr lst, i));
  382. end;
  383. % The function subst(a1,a2,a3) substitutes a1 for all occurences
  384. % of a2 in list a3
  385. % Allows printing out two variables. Usually a
  386. % string and a variable.
  387. symbolic procedure debug(s1, s2);
  388. begin;
  389. terpri!* t;
  390. princ s1; princ s2;
  391. terpri!* t;
  392. end;
  393. % If v=t then there is a 2 space indentation,
  394. % if v=nil then the next print will be
  395. % 2 spaces less.
  396. fluid '(indent ind);
  397. symbolic procedure indent!* (v);
  398. begin;
  399. if v=t then indent:=indent+ind;
  400. if v=nil then indent:=indent-ind;
  401. end;
  402. end;