mes_read.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. /* -*-comment-start: "//";comment-end:""-*-
  2. * GNU Mes --- Maxwell Equations of Software
  3. * Copyright © 2016,2017,2018 Jan (janneke) Nieuwenhuizen <janneke@gnu.org>
  4. * Copyright © 2019 Jeremiah Orians
  5. *
  6. * This file is part of GNU Mes.
  7. *
  8. * GNU Mes is free software; you can redistribute it and/or modify it
  9. * under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 3 of the License, or (at
  11. * your option) any later version.
  12. *
  13. * GNU Mes is distributed in the hope that it will be useful, but
  14. * WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with GNU Mes. If not, see <http://www.gnu.org/licenses/>.
  20. */
  21. #include "mes.h"
  22. int in_set(int c, char* s);
  23. /****************************************
  24. * Deal with terriable inputs *
  25. ****************************************/
  26. int scrub_byte(FILE* source_file)
  27. {
  28. int c = fgetc(source_file);
  29. require(0 != c, "mes-m2 does not support null characters as input\n");
  30. require(127 > c, "mes-m2 does not support utf-8 at this time\nplease restrict yourself to 7bit ascii\n");
  31. return c;
  32. }
  33. /****************************************************
  34. * Clear out everything between #!..!# and #|..|# *
  35. ****************************************************/
  36. void reader_read_block_comment(FILE* source_file, int match)
  37. {
  38. int last = 0;
  39. int current = fgetc(source_file);
  40. while((match != last) || ('#' != current))
  41. {
  42. require(EOF != current, "Unterminated block comment found\n");
  43. last = current;
  44. current = fgetc(source_file);
  45. }
  46. }
  47. /****************************************************
  48. * Deal with #;foo and #;( foo ..) S-Expressions *
  49. ****************************************************/
  50. void reader_s_expression_dump(FILE* source_file)
  51. {
  52. int c = scrub_byte(source_file);
  53. unsigned depth = 0;
  54. /* Clear out leading whitespace */
  55. while(in_set(c, " \t\n"))
  56. {
  57. c = scrub_byte(source_file);
  58. require(EOF != c, "#; s-expression not bounded\n");
  59. }
  60. while(TRUE)
  61. {
  62. require(EOF != c, "#; s-expression not bounded\n");
  63. if(4 == c)
  64. {
  65. return;
  66. }
  67. else if((0 == depth) && (in_set(c, " \t\n\r")))
  68. {
  69. return;
  70. }
  71. else if('(' == c)
  72. {
  73. depth = depth + 1;
  74. }
  75. else if(')' == c)
  76. {
  77. depth = depth - 1;
  78. if(0 == depth) return;
  79. }
  80. c = scrub_byte(source_file);
  81. }
  82. }
  83. /****************************************************
  84. * Do the heavy lifting of reading an s-expression *
  85. ****************************************************/
  86. unsigned Readline(FILE* source_file, char* temp)
  87. {
  88. int c;
  89. unsigned i = 0;
  90. unsigned depth = 0;
  91. int hashed = FALSE;
  92. int escape = FALSE;
  93. while(TRUE)
  94. {
  95. restart_comment:
  96. c = scrub_byte(source_file);
  97. restart_paren:
  98. require(i < MAX_STRING, "s-expression exceeds max size\nExpand MES_MAX_STRING value to resolve\n");
  99. if((EOF == c) || (4 == c))
  100. {
  101. require(0 == depth, "Unmatched s-expression\n");
  102. return i;
  103. }
  104. else if('#' == c)
  105. {
  106. hashed = TRUE;
  107. goto restart_comment;
  108. }
  109. else if (hashed && in_set(c, "!|"))
  110. {
  111. reader_read_block_comment(source_file, c);
  112. hashed = FALSE;
  113. goto restart_comment;
  114. }
  115. else if(in_set(c, "\'`"))
  116. {
  117. temp[i] = c;
  118. temp[i+1] = ' ';
  119. i = i + 1;
  120. }
  121. else if(',' == c)
  122. {
  123. c = scrub_byte(source_file);
  124. temp[i] = ',';
  125. i = i + 1;
  126. if('@' == c)
  127. {
  128. temp[i] = '@';
  129. i = i + 1;
  130. c = ' ';
  131. }
  132. temp[i] = ' ';
  133. i = i + 1;
  134. goto restart_paren;
  135. }
  136. else if(hashed && (';' == c))
  137. {
  138. reader_s_expression_dump(source_file);
  139. hashed = FALSE;
  140. c = ' ';
  141. goto restart_paren;
  142. }
  143. else if(hashed && ('\\' == c))
  144. {
  145. temp[i] = '#';
  146. temp[i+1] = '\\';
  147. c = scrub_byte(source_file);
  148. i = i + 2;
  149. hashed = FALSE;
  150. /* Deal with the really special cases */
  151. if(in_set(c, "#;\"()"))
  152. {
  153. temp[i] = c;
  154. temp[i+1] = ' ';
  155. i = i + 2;
  156. goto restart_comment;
  157. }
  158. goto restart_paren;
  159. }
  160. else if(';' == c)
  161. {
  162. /* drop everything until we hit newline */
  163. while('\n' != c)
  164. {
  165. c = fgetc(source_file);
  166. require(EOF != c, "recieved EOF in line comment, please add newline at end of file\n");
  167. }
  168. goto restart_comment;
  169. }
  170. else if('"' == c)
  171. { /* Deal with strings */
  172. do
  173. {
  174. if(!escape && '\\' == c ) escape = TRUE;
  175. else escape = FALSE;
  176. temp[i] = c;
  177. i = i + 1;
  178. c = scrub_byte(source_file);
  179. require(EOF != c, "s-expression string does not have matching \"\n");
  180. require(i < MAX_STRING, "s-expression string exceeded limit of s-expression\nExpand MES_MAX_STRING value to resolve\n");
  181. } while('"' != c || escape);
  182. temp[i] = c;
  183. }
  184. else if((0 == depth) && in_set(c, " \t\n\r"))
  185. {
  186. goto Line_complete;
  187. }
  188. else if(in_set(c, "()"))
  189. {
  190. if('(' == c)
  191. {
  192. depth = depth + 1;
  193. }
  194. if(')' == c)
  195. {
  196. depth = depth - 1;
  197. }
  198. if(hashed)
  199. {
  200. temp[i] = '#';
  201. temp[i+1] = c;
  202. temp[i+2] = ' ';
  203. i = i + 2;
  204. hashed = FALSE;
  205. }
  206. else
  207. {
  208. temp[i] = ' ';
  209. temp[i+1] = c;
  210. temp[i+2] = ' ';
  211. i = i + 2;
  212. }
  213. c = ' ';
  214. goto restart_paren;
  215. }
  216. else if(hashed)
  217. {
  218. temp[i] = '#';
  219. temp[i+1] = c;
  220. i = i + 1;
  221. hashed = FALSE;
  222. }
  223. else
  224. {
  225. temp[i] = c;
  226. }
  227. i = i + 1;
  228. }
  229. Line_complete:
  230. if(0 == i)
  231. {
  232. return Readline(source_file, temp);
  233. }
  234. return i;
  235. }