sceql-0.1.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. /*
  2. The Sceql specification is not set in stone, so this
  3. interpreter may change in the future. Version 0.1 of the specification
  4. is implemented here.
  5. */
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <limits.h>
  9. #define NODESIZE 1000
  10. #define LOOPDEPTH 1000
  11. typedef unsigned char byte;
  12. typedef struct byteqnode
  13. {
  14. byte qdata[NODESIZE];
  15. int start; /* the first byte in use in qdata */
  16. int end; /* the last byte in use in qdata */
  17. struct byteqnode *next;
  18. } byteqnode;
  19. typedef struct
  20. {
  21. int len;
  22. byteqnode *head, *tail;
  23. } bytequeue;
  24. void error(char *complaint)
  25. {
  26. fprintf(stderr, "%s\n", complaint);
  27. exit(1);
  28. }
  29. /* create a queue with a zero byte in it */
  30. bytequeue *queue_create(void)
  31. {
  32. bytequeue *myq;
  33. myq = malloc(sizeof (bytequeue));
  34. if (!myq)
  35. error("Out of memory");
  36. myq->len = 1;
  37. myq->head = myq->tail = malloc(sizeof (byteqnode));
  38. if (!myq->head)
  39. error("Out of memory");
  40. myq->tail->next = NULL;
  41. myq->tail->start = myq->tail->end = 0;
  42. myq->tail->qdata[0] = 0;
  43. return myq;
  44. }
  45. /* add a byte onto the back of the queue */
  46. void queue_enqueue(bytequeue *q, byte val)
  47. {
  48. byteqnode *node;
  49. node = q->tail;
  50. node->end++;
  51. if (node->end == NODESIZE)
  52. {
  53. node = q->tail = node->next = malloc(sizeof (byteqnode));
  54. if (!node)
  55. error("Out of memory");
  56. node->next = NULL;
  57. node->start = node->end = 0;
  58. }
  59. node->qdata[node->end] = val;
  60. q->len++;
  61. }
  62. byte queue_peek(bytequeue *q);
  63. /* take a byte from the front of the queue */
  64. byte queue_dequeue(bytequeue *q)
  65. {
  66. byte result;
  67. result = queue_peek(q);
  68. q->head->start++;
  69. if (q->head->start == NODESIZE)
  70. {
  71. byteqnode *node = q->head->next;
  72. free(q->head);
  73. q->head = node;
  74. /* q->head->start should already be 0 */
  75. }
  76. q->len--;
  77. return result;
  78. }
  79. /* peek at a byte from the front of the queue */
  80. byte queue_peek(bytequeue *q)
  81. {
  82. if (q->len == 0)
  83. error("peeking at an empty queue");
  84. return q->head->qdata[q->head->start];
  85. }
  86. /* shove a new byte at the front of the queue replacing what's there */
  87. void queue_shove(bytequeue *q, byte b)
  88. {
  89. if (q->len == 0)
  90. error("shoving into an empty queue");
  91. q->head->qdata[q->head->start] = b;
  92. }
  93. void queue_delete(bytequeue *q)
  94. {
  95. byteqnode *node;
  96. while (q->head)
  97. {
  98. node = q->head->next;
  99. free(q->head);
  100. q->head = node;
  101. }
  102. free(q);
  103. }
  104. #ifdef DEBUGGING
  105. void queue_debug(bytequeue *q)
  106. {
  107. int i;
  108. i = q->len;
  109. if (i > 0)
  110. {
  111. byte b;
  112. b = queue_dequeue(q);
  113. printf("%d", b);
  114. queue_enqueue(q, b);
  115. }
  116. for (i--; i > 0; i--)
  117. {
  118. byte b;
  119. b = queue_dequeue(q);
  120. printf(", %d", b);
  121. queue_enqueue(q, b);
  122. }
  123. putchar('\n');
  124. }
  125. #endif
  126. typedef enum
  127. {
  128. IN_NEXT = 0x01,
  129. IN_DEC = 0x02,
  130. IN_INPUT = 0x03,
  131. IN_OUTPUT = 0x04,
  132. IN_INC = 0x05,
  133. IN_GROW = 0x06,
  134. IN_BEGIN = 0x10,
  135. IN_END = 0x11
  136. #ifdef DEBUGGING
  137. ,IN_DEBUG = 0xff
  138. #endif
  139. } sceql_intype;
  140. typedef struct
  141. {
  142. sceql_intype in;
  143. int r;
  144. } sceql_instruction;
  145. typedef struct
  146. {
  147. sceql_instruction *code;
  148. int len;
  149. } sceql_program;
  150. sceql_intype sceql_getinstruction(FILE *f)
  151. {
  152. static sceql_intype uc2i[UCHAR_MAX + 1] = { IN_BEGIN };
  153. int c;
  154. sceql_intype i;
  155. if (uc2i[0] == IN_BEGIN)
  156. {
  157. uc2i[0] = 0;
  158. for (c = 1; c <= (int) UCHAR_MAX; c++)
  159. {
  160. i = 0;
  161. if (c == '\\')
  162. i = IN_BEGIN;
  163. else if (c == '/')
  164. i = IN_END;
  165. else if (c == '=')
  166. i = IN_NEXT;
  167. else if (c == '-')
  168. i = IN_DEC;
  169. else if (c == '_')
  170. i = IN_INC;
  171. else if (c == '!')
  172. i = IN_GROW;
  173. else if (c == '&')
  174. i = IN_INPUT;
  175. else if (c == '*')
  176. i = IN_OUTPUT;
  177. #ifdef DEBUGGING
  178. else if (c == '`')
  179. i = IN_DEBUG;
  180. #endif
  181. uc2i[c] = i;
  182. }
  183. }
  184. for (;;)
  185. {
  186. c = fgetc(f);
  187. if (c < 0 || c > 255)
  188. return 0;
  189. if ((i = uc2i[c]))
  190. break;
  191. }
  192. return i;
  193. }
  194. void sceql_load(sceql_program *p, FILE *f)
  195. {
  196. sceql_instruction *code;
  197. sceql_intype in;
  198. unsigned long filesize;
  199. int last = 0, depth = 0, begin[LOOPDEPTH];
  200. fseek(f, 0, SEEK_END);
  201. filesize = ftell(f);
  202. if (filesize > INT_MAX)
  203. error("File too long");
  204. fseek(f, 0, SEEK_SET);
  205. code = p->code = malloc(filesize * sizeof (sceql_instruction));
  206. if (!code)
  207. error("Not enough memory");
  208. if (!(in = sceql_getinstruction(f)))
  209. error("Program contains no instructions");
  210. if (in == IN_END)
  211. error("Unbalanced slashes");
  212. if (in == IN_BEGIN)
  213. begin[depth++] = 0;
  214. code[0].in = in;
  215. code[0].r = 1;
  216. while ((in = sceql_getinstruction(f)))
  217. {
  218. if (in == IN_BEGIN)
  219. {
  220. last++;
  221. if (depth < LOOPDEPTH)
  222. begin[depth] = last;
  223. depth++;
  224. }
  225. else if (in == IN_END && depth <= LOOPDEPTH)
  226. {
  227. if (!depth)
  228. error("Unbalanced slashes");
  229. last++;
  230. code[last].r = last - begin[--depth];
  231. code[begin[depth]].r = code[last].r + 1;
  232. }
  233. else if (in == IN_END)
  234. {
  235. int mydepth = depth, start;
  236. for (start = last++; start >= 0; start--)
  237. {
  238. if (code[start].in == IN_BEGIN)
  239. {
  240. if (mydepth == depth)
  241. break;
  242. mydepth--;
  243. }
  244. else if (code[start].in == IN_END)
  245. mydepth++;
  246. }
  247. code[last].r = last - start;
  248. code[start].r = code[last].r + 1;
  249. depth--;
  250. }
  251. else
  252. {
  253. if (in == code[last].in)
  254. {
  255. code[last].r++;
  256. continue;
  257. }
  258. code[++last].r = 1;
  259. }
  260. code[last].in = in;
  261. }
  262. fclose(f);
  263. if (depth)
  264. error("Unbalanced slashes");
  265. p->len = last + 1;
  266. }
  267. void sceql_run(sceql_program *p)
  268. {
  269. bytequeue *q;
  270. sceql_instruction *ip, *end;
  271. ip = p->code;
  272. end = ip + p->len;
  273. q = queue_create();
  274. do
  275. {
  276. register sceql_intype in;
  277. register int r;
  278. in = ip->in;
  279. r = ip->r;
  280. /* run the instruction "in": not just once, but "r" times */
  281. if (in == IN_NEXT)
  282. {
  283. register byte b;
  284. for (; r; r--)
  285. {
  286. b = queue_dequeue(q);
  287. queue_enqueue(q, b);
  288. }
  289. }
  290. /* it just so happens that we can increment or decrement
  291. r times with a one-liner */
  292. else if (in == IN_INC)
  293. queue_shove(q, queue_peek(q) + r);
  294. else if (in == IN_DEC)
  295. queue_shove(q, queue_peek(q) - r);
  296. else if (in == IN_GROW)
  297. {
  298. for (; r; r--)
  299. queue_enqueue(q, 0);
  300. }
  301. else if (in == IN_OUTPUT)
  302. {
  303. register int c;
  304. for (; r; r--)
  305. {
  306. c = queue_dequeue(q);
  307. putchar(c);
  308. queue_enqueue(q, c);
  309. }
  310. }
  311. else if (in == IN_INPUT)
  312. {
  313. register int c;
  314. for (; r; r--)
  315. {
  316. c = getchar();
  317. if (c == EOF)
  318. c = 0;
  319. queue_enqueue(q, c);
  320. }
  321. }
  322. else if (in == IN_BEGIN)
  323. {
  324. register byte b;
  325. if (!(b = queue_peek(q)))
  326. {
  327. ip += r;
  328. continue;
  329. }
  330. }
  331. #ifdef DEBUGGING
  332. else if (in == IN_DEBUG)
  333. queue_debug(q);
  334. #endif
  335. else /* in == IN_END */
  336. {
  337. ip -= r;
  338. continue;
  339. }
  340. ip++;
  341. } while (ip < end);
  342. queue_delete(q);
  343. }
  344. void sceql_freeup(sceql_program *p)
  345. {
  346. free(p->code);
  347. }
  348. void sceql_do(FILE *f)
  349. {
  350. sceql_program prog;
  351. sceql_load(&prog, f);
  352. sceql_run(&prog);
  353. sceql_freeup(&prog);
  354. }
  355. int main(int argc, char *argv[])
  356. {
  357. FILE *codesrc = stdin;
  358. if (argc != 2)
  359. error("usage: sceql [sourcefile.sceql]");
  360. if (!(codesrc = fopen(argv[1], "r")))
  361. {
  362. error("Unable to open file");
  363. }
  364. sceql_do(codesrc);
  365. return 0;
  366. }