Annotation of OpenXM/src/ox_toolkit/parse.c, Revision 1.2
1.1 ohara 1: /* -*- mode: C; coding: euc-japan -*- */
1.2 ! ohara 2: /* $OpenXM: OpenXM/src/ox_toolkit/parse.c,v 1.1 1999/12/09 22:44:56 ohara Exp $ */
1.1 ohara 3:
4: /* OX expression, CMO expression パーサ */
5:
6: #include <stdio.h>
7: #include <stdlib.h>
8: #include <string.h>
9: #include <sys/param.h>
10: #include <setjmp.h>
11: #include "oxtag.h"
12: #include "ox.h"
13: #include "parse.h"
14:
15: /* --- 構文解析部 --- */
16: /* (重要)セマンティックスについての注意.
17: CMO_LIST, CMO_STRING は、あらかじめ与えられた要素の個数を無視する.
18: CMO_MONOMIAL32 は無視しない. (つまりおかしいときは構文エラーになる)
19: */
20:
21: /* parse.c, lex.c では, Lisp 表現された CMO 文字列を読み込み,
22: バイト列を出力する. 中間表現として、cmo 構造体を利用する.
23: parse() はトークンの列から cmo 構造体を生成し、そのポインタを返す.
24: */
25:
26: /* 重要なことはパーサ(の各サブルーチン)は
27: 常にトークンをひとつ先読みしていると言うことである.
28: */
29:
30: /* 現在読み込み中のトークンを表す. */
31: static int token = 0;
32:
33: /* トークンの属性値. yylval は lex() によってセットされる. */
34: static union{
35: int d;
36: char *sym;
37: } yylval;
38:
39: /* pflag_cmo_addrev がセットされていれば、厳密には CMO expression では
40: ないもの, 例えば (CMO_STRING, "hello") も CMO に変換される. */
41:
42: static int pflag_cmo_addrev = 1; /* CMO の省略記法を許すか否かのフラグ */
43:
44: /* 関数の宣言 */
45: static int parse_error(char *s);
46: static int parse_lf();
47: static int parse_right_parenthesis();
48: static int parse_left_parenthesis();
49: static int parse_comma();
50: static int parse_integer();
51: static char *parse_string();
52: static cmo *parse_cmo_null();
53: static cmo *parse_cmo_int32();
54: static cmo *parse_cmo_string();
55: static cmo *parse_cmo_mathcap();
56: static cmo *parse_cmo_list();
57: static cmo *parse_cmo_monomial32();
58: static cmo *parse_cmo_zz();
59: static cmo *parse_cmo_zero();
60: static cmo *parse_cmo_dms_generic();
61: static cmo *parse_cmo_ring_by_name();
62: static cmo *parse_cmo_distributed_polynomial();
63: static cmo *parse_cmo_indeterminate();
64: static cmo *parse_cmo_error2();
65: static cmo *parse_cmo();
66: static int parse_sm();
67: static ox *parse_ox();
68: static ox *parse_ox_command();
69: static ox *parse_ox_data();
70:
71: static int is_token_cmo(int token)
72: {
73: return (token >= MIN_T_CMO && token < MAX_T_CMO) || token == TOKEN(CMO_ERROR2);
74: }
75:
76: static int is_token_sm(int token)
77: {
78: return token == TOKEN(SM);
79: }
80:
81: static int is_token_ox(int token)
82: {
83: return token >= MIN_T_OX && token < MAX_T_OX;
84: }
85:
86: static jmp_buf env_parse;
87:
88: /* 構文解析に失敗したことを意味する. */
89: static int parse_error(char *s)
90: {
91: fprintf(stderr, "syntax error: %s\n", s);
92: longjmp(env_parse, 1);
93: }
94:
1.2 ! ohara 95: int setflag_parse(int flag)
! 96: {
! 97: pflag_cmo_addrev = flag;
! 98: }
! 99:
! 100: int init_parser(char *s)
! 101: {
! 102: setflag_parse(PFLAG_ADDREV);
! 103: setmode_mygetc(s);
! 104: }
! 105:
1.1 ohara 106: /* この部分は書き換え予定. */
107: cmo *parse()
108: {
109: cmo *m;
110:
111: if (setjmp(env_parse) != 0) {
112: return NULL; /* 構文解析に失敗したら NULL を返す. */
113: }
114:
115: do{
116: token = lex();
117: }while (token == '\n');
118:
119: if (token == '(') {
120: token = lex();
121: if (is_token_cmo(token)) {
122: m = parse_cmo();
123: }else if(is_token_ox(token)) {
124: m = parse_ox();
125: }else {
126: parse_error("invalid symbol.");
127: }
1.2 ! ohara 128: /* parse_lf(); */
1.1 ohara 129: return m;
130: }
131: return NULL;
132: }
133:
134: /* トークンを先読みしない(重要). */
135: static int parse_lf()
136: {
137: if (token != '\n') {
138: parse_error("no new line.");
139: }
140: return 0;
141: }
142:
143:
144: static ox *parse_ox()
145: {
146: ox *m = NULL;
147:
148: switch(token) {
149: case TOKEN(OX_COMMAND):
150: token = lex();
151: m = parse_ox_command();
152: break;
153: case TOKEN(OX_DATA):
154: token = lex();
155: m = parse_ox_data();
156: break;
157: default:
158: parse_error("invalid ox.");
159: }
160: return m;
161: }
162:
163: static ox *parse_ox_data()
164: {
165: ox *m;
166:
167: parse_comma();
168: parse_left_parenthesis();
169: m = (ox *)new_ox_data(parse_cmo());
170: parse_right_parenthesis();
171: return m;
172: }
173:
174: static ox *parse_ox_command()
175: {
176: ox *m;
177:
178: parse_comma();
179: parse_left_parenthesis();
180: m = (ox *)new_ox_command(parse_sm());
181: parse_right_parenthesis();
182: return m;
183: }
184:
185: static int parse_sm()
186: {
187: int sm_code;
188: if (token != TOKEN(SM)) {
189: parse_error("no opecode.");
190: }
191: sm_code = yylval.d;
192: token = lex();
193: parse_right_parenthesis();
194: return sm_code;
195: }
196:
197:
198: /* 正しい入力ならば, parse_cmo を呼ぶ時点で, token には
199: TOKEN(CMO_xxx), TOKEN(OX_xxx) のいずれかがセットされている. */
200: static cmo *parse_cmo()
201: {
202: cmo *m = NULL;
203:
204: switch(token) {
205: case TOKEN(CMO_NULL):
206: token = lex();
207: m = parse_cmo_null();
208: break;
209: case TOKEN(CMO_INT32):
210: token = lex();
211: m = parse_cmo_int32();
212: break;
213: case TOKEN(CMO_STRING):
214: token = lex();
215: m = parse_cmo_string();
216: break;
217: case TOKEN(CMO_MATHCAP):
218: token = lex();
219: m = parse_cmo_mathcap();
220: break;
221: case TOKEN(CMO_LIST):
222: token = lex();
223: m = parse_cmo_list();
224: break;
225: case TOKEN(CMO_MONOMIAL32):
226: token = lex();
227: m = parse_cmo_monomial32();
228: break;
229: case TOKEN(CMO_ZZ):
230: token = lex();
231: m = parse_cmo_zz();
232: break;
233: case TOKEN(CMO_ZERO):
234: token = lex();
235: m = parse_cmo_zero();
236: break;
237: case TOKEN(CMO_DMS_GENERIC):
238: token = lex();
239: m = parse_cmo_dms_generic();
240: break;
241: case TOKEN(CMO_RING_BY_NAME):
242: token = lex();
243: m = parse_cmo_ring_by_name();
244: break;
245: case TOKEN(CMO_DISTRIBUTED_POLYNOMIAL):
246: token = lex();
247: m = parse_cmo_distributed_polynomial();
248: break;
249: case TOKEN(CMO_INDETERMINATE):
250: token = lex();
251: m = parse_cmo_indeterminate();
252: break;
253: case TOKEN(CMO_ERROR2):
254: token = lex();
255: m = parse_cmo_error2();
256: break;
257: default:
258: parse_error("invalid cmo.");
259: }
260: return m;
261: }
262:
263: static int parse_left_parenthesis()
264: {
265: if (token != '(') {
266: parse_error("no left parenthesis.");
267: }
268: token = lex();
269: }
270:
271: static int parse_right_parenthesis()
272: {
273: if (token != ')') {
274: parse_error("no right parenthesis.");
275: }
276: token = lex();
277: }
278:
279: static int parse_comma()
280: {
281: if (token != ',') {
282: parse_error("no comma.");
283: }
284: token = lex();
285: }
286:
287: static int parse_integer()
288: {
289: int val;
290: if (token != T_INTEGER) {
291: parse_error("no integer.");
292: }
293: val = yylval.d;
294: token = lex();
295: return val;
296: }
297:
298: static char *parse_string()
299: {
300: char *s;
301: if (token != T_STRING) {
302: parse_error("no string.");
303: }
304: s = yylval.sym;
305: token = lex();
306: return s;
307: }
308:
309: static cmo *parse_cmo_null()
310: {
311: parse_right_parenthesis();
312: return (cmo *)new_cmo_null();
313: }
314:
315: static cmo *parse_cmo_int32()
316: {
317: int i;
318:
319: parse_comma();
320: i = parse_integer();
321: parse_right_parenthesis();
322: return (cmo *)new_cmo_int32(i);
323: }
324:
325: static cmo *parse_cmo_string()
326: {
327: cmo_string *m;
328: char *s;
329:
330: parse_comma();
331: if (token == T_INTEGER) {
332: parse_integer();
333: parse_comma();
334: }else if (!pflag_cmo_addrev) {
335: parse_error("invalid cmo string.");
336: }
337: s = parse_string();
338: m = new_cmo_string(s);
339: parse_right_parenthesis();
340: return (cmo *)m;
341: }
342:
343: static cmo *parse_cmo_mathcap()
344: {
345: cmo *ob;
346:
347: parse_comma();
348: parse_left_parenthesis();
349: ob = parse_cmo();
350: parse_right_parenthesis();
351: return (cmo *)new_cmo_mathcap(ob);
352: }
353:
354: static cmo *parse_cmo_list()
355: {
356: int length=0;
357: int i=0;
358: cmo_list *m = new_cmo_list();
359: cmo *newcmo;
360:
361: if (token == ',') {
362: parse_comma();
363:
364: if (token == T_INTEGER) {
365: parse_integer();
366: parse_comma();
367: }else if (!pflag_cmo_addrev) {
368: parse_error("invalid cmo_list.");
369: }
370:
371: while(token == '(') {
372: parse_left_parenthesis();
373: newcmo = parse_cmo();
374: append_cmo_list(m, newcmo);
375: if (token != ',') {
376: break;
377: }
378: parse_comma();
379: }
380: }else if (!pflag_cmo_addrev) {
381: parse_error("invalid cmo_list.");
382: }
383: parse_right_parenthesis();
384: return (cmo *)m;
385: }
386:
387: static cmo *parse_cmo_monomial32()
388: {
389: int size;
390: int *exps;
391: int i;
392: cmo_monomial32 *m;
393: int tag;
394:
395: parse_comma();
396: size = parse_integer();
397: if (size < 0) {
398: parse_error("invalid value.");
399: }
400: m = new_cmo_monomial32_size(size);
401:
402: for(i=0; i<size; i++) {
403: parse_comma();
404: m->exps[i] = parse_integer();
405: }
406: parse_comma();
407: parse_left_parenthesis();
408: m->coef = parse_cmo();
409: tag = m->coef->tag;
410:
411: /* m->coef は CMO_ZZ 型か CMO_INT32 型でなければならない */
412: if (tag != CMO_ZZ && tag != CMO_INT32) {
413: parse_error("invalid cmo.");
414: }
415: parse_right_parenthesis();
416: return (cmo *)m;
417: }
418:
419: /* cmo_zz の内部を直接いじる. */
420: static cmo *parse_cmo_zz()
421: {
422: int length;
423: int i=0;
424: cmo_zz *m= NULL;
425:
426: parse_comma();
427: length = parse_integer();
428: if (token == ',') {
429: m = new_cmo_zz_size(length);
430:
431: length = abs(length);
432: for(i=0; i<length; i++) {
433: parse_comma();
434: m->mpz->_mp_d[i] = parse_integer();
435: }
436: }else if (pflag_cmo_addrev) {
437: m = new_cmo_zz_set_si(length);
438: }else {
439: parse_error("no comma.");
440: }
441:
442: parse_right_parenthesis();
443: return (cmo *)m;
444: }
445:
446: static cmo *parse_cmo_zero()
447: {
448: parse_right_parenthesis();
449: return (cmo *)new_cmo_zero();
450: }
451:
452: static cmo *parse_cmo_dms_generic()
453: {
454: parse_right_parenthesis();
455: return (cmo *)new_cmo_dms_generic();
456: }
457:
458: static cmo *parse_cmo_ring_by_name()
459: {
460: cmo *ob;
461:
462: parse_comma();
463: parse_left_parenthesis();
464: ob = parse_cmo();
465:
466: /* ob は CMO_STRING 型でなければならない */
467: if (ob->tag != CMO_STRING) {
468: parse_error("invalid cmo.");
469: }
470: parse_right_parenthesis();
471: return (cmo *)new_cmo_ring_by_name(ob);
472: }
473:
474: static cmo *parse_cmo_distributed_polynomial()
475: {
476: int length=0;
477: int i=0;
478: cmo_distributed_polynomial *m = new_cmo_distributed_polynomial();
479: cmo *ob;
480: int tag;
481:
482: if (token == ',') {
483: parse_comma();
484:
485: if (token == T_INTEGER) {
486: parse_integer();
487: parse_comma();
488: }else if (!pflag_cmo_addrev) {
489: parse_error("invalid d-polynomial.");
490: }
491:
492: parse_left_parenthesis();
493: m->ringdef = parse_cmo();
494: tag = m->ringdef->tag;
495: /* m->ringdef は DringDefinition でなければならない */
496: if (tag != CMO_RING_BY_NAME && tag != CMO_DMS_GENERIC
497: && tag != CMO_DMS_OF_N_VARIABLES) {
498: parse_error("invalid cmo.");
499: }
500:
501: parse_comma();
502:
503: while(token == '(') {
504: parse_left_parenthesis();
505: ob = parse_cmo();
506: if (ob->tag != CMO_MONOMIAL32 && ob->tag != CMO_ZERO) {
507: parse_error("invalid cmo.");
508: }
509: append_cmo_list((cmo_list *)m, ob);
510: if (token != ',') {
511: break;
512: }
513: parse_comma();
514: }
515: }else if (!pflag_cmo_addrev) {
516: parse_error("invalid d-polynomial.");
517: }
518: parse_right_parenthesis();
519: return (cmo *)m;
520: }
521:
522: static cmo *parse_cmo_indeterminate()
523: {
524: cmo *ob;
525:
526: parse_comma();
527: parse_left_parenthesis();
528: ob = parse_cmo();
529: parse_right_parenthesis();
530: return (cmo *)new_cmo_indeterminate(ob);
531: }
532:
533: static cmo *parse_cmo_error2()
534: {
535: cmo *ob;
536:
537: parse_comma();
538: parse_left_parenthesis();
539: ob = parse_cmo();
540: parse_right_parenthesis();
541: return (cmo *)new_cmo_error2(ob);
542: }
543:
544: /* --- 字句解析部 --- */
545:
546: /* lexical analyzer で読み飛ばされる文字なら何を初期値にしてもよい */
547: static int c = ' ';
548:
549: /* 一文字読み込む関数 */
1.2 ! ohara 550: static char *mygetc_ptr;
! 551: static int mygetc()
! 552: {
! 553: return *mygetc_ptr++;
! 554: }
1.1 ohara 555:
1.2 ! ohara 556: int setmode_mygetc(char *s)
1.1 ohara 557: {
1.2 ! ohara 558: mygetc_ptr=s;
1.1 ohara 559: }
560:
1.2 ! ohara 561: static int (*GETC)() = mygetc;
! 562:
! 563: /* 一文字読み込む関数の選択 (ex. setgetc(getchar); ) */
! 564: int setgetc(int (*foo)())
1.1 ohara 565: {
1.2 ! ohara 566: if (foo == NULL) {
! 567: GETC = mygetc;
! 568: }else {
! 569: GETC = foo;
! 570: }
1.1 ohara 571: }
572:
573: #define SIZE_BUFFER 8192
574: static char buffer[SIZE_BUFFER];
575:
576: /* 桁溢れの場合の対策はない */
577: static int lex_digit()
578: {
579: int d = 0;
580: do {
581: d = 10*d + (c - '0');
582: c = GETC();
583: } while(isdigit(c));
584: return d;
585: }
586:
587: #define MK_KEY_CMO(x) { #x , x , TOKEN(x) , IS_CMO }
588: #define MK_KEY_SM(x) { #x , x , TOKEN(SM) , IS_SM }
589: #define MK_KEY_OX(x) { #x , x , TOKEN(x) , IS_OX }
590:
591: static symbol symbol_list[] = {
592: MK_KEY_CMO(CMO_NULL),
593: MK_KEY_CMO(CMO_INT32),
594: MK_KEY_CMO(CMO_DATUM),
595: MK_KEY_CMO(CMO_STRING),
596: MK_KEY_CMO(CMO_MATHCAP),
597: MK_KEY_CMO(CMO_LIST),
598: MK_KEY_CMO(CMO_MONOMIAL32),
599: MK_KEY_CMO(CMO_ZZ),
600: MK_KEY_CMO(CMO_ZERO),
601: MK_KEY_CMO(CMO_DMS_GENERIC),
602: MK_KEY_CMO(CMO_RING_BY_NAME),
603: MK_KEY_CMO(CMO_INDETERMINATE),
604: MK_KEY_CMO(CMO_DISTRIBUTED_POLYNOMIAL),
605: MK_KEY_CMO(CMO_ERROR2),
606: MK_KEY_SM(SM_popCMO),
607: MK_KEY_SM(SM_popString),
608: MK_KEY_SM(SM_mathcap),
609: MK_KEY_SM(SM_pops),
610: MK_KEY_SM(SM_executeStringByLocalParser),
611: MK_KEY_SM(SM_executeFunction),
612: MK_KEY_SM(SM_setMathCap),
613: MK_KEY_SM(SM_shutdown),
614: MK_KEY_SM(SM_control_kill),
615: MK_KEY_SM(SM_control_reset_connection),
616: MK_KEY_OX(OX_COMMAND),
617: MK_KEY_OX(OX_DATA),
618: {NULL, 0, 0, 0} /* a gate keeper */
619: };
620:
621: symbol* lookup_by_symbol(char *key)
622: {
623: symbol *symp;
624: for(symp = symbol_list; symp->key != NULL; symp++) {
625: if (strcmp(key, symp->key)==0) {
626: return symp;
627: }
628: }
629: return NULL;
630: }
631:
632: symbol* lookup_by_token(int tok)
633: {
634: symbol *symp;
635: for(symp = symbol_list; symp->key != NULL; symp++) {
636: if (tok == symp->token) {
637: return symp;
638: }
639: }
640: return NULL;
641: }
642:
643: symbol* lookup_by_tag(int tag)
644: {
645: symbol *symp;
646: for(symp = symbol_list; symp->key != NULL; symp++) {
647: if (tag == symp->tag) {
648: return symp;
649: }
650: }
651: return NULL;
652: }
653:
654: symbol* lookup(int i)
655: {
656: return &symbol_list[i];
657: }
658:
659: /* バッファあふれした場合の対策をちゃんと考えるべき */
660: static char *lex_quoted_string()
661: {
662: int i;
663: char c0 = ' ';
664: char *s = NULL;
665: for (i=0; i<SIZE_BUFFER; i++) {
666: c = GETC();
667: if(c == '"') {
668: s = malloc(i+1);
669: buffer[i]='\0';
670: strcpy(s, buffer);
671:
672: c = GETC();
673: return s;
674: }else if (c == '\\') {
675: c0 = c;
676: c = GETC();
677: if (c != '"') {
678: buffer[i++] = c0;
679: }
680: }
681: buffer[i]=c;
682: }
683: fprintf(stderr, "buffer overflow!\n");
684: exit(1);
685: /* return NULL; */
686: }
687:
688: static int token_of_symbol(char *key)
689: {
690: symbol *symp = lookup_by_symbol(key);
691: if (symp != NULL) {
692: yylval.d = symp->tag;
693: return symp->token;
694: }
695: #if DEBUG
696: fprintf(stderr, "lex error:: \"%s\" is unknown symbol.\n", key);
697: #endif
698: return 0;
699: }
700:
701: static int lex_symbol()
702: {
703: int i;
704: for (i=0; i<SIZE_BUFFER; i++) {
705: if (!isalnum(c) && c != '_') {
706: buffer[i]='\0';
707: return token_of_symbol(buffer);
708: }
709: buffer[i]=c;
710: c = GETC();
711: }
712: fprintf(stderr, "buffer overflow!\n");
713: return 0;
714: }
715:
716: /* return する前に一文字先読みしておく. */
717: int lex()
718: {
719: int c_dash = 0;
720:
721: /* 空白をスキップする. */
722: while (isspace(c) && c != '\n') {
723: c = GETC();
724: }
725:
726: switch(c) {
727: case '(':
728: case ')':
729: case ',':
730: case '\n':
731: c_dash = c;
732: c = ' ';
733: return c_dash;
734: case EOF:
735: c = GETC();
736: return c_dash;
737: case '"': /* a quoted string! */
738: yylval.sym = lex_quoted_string();
739: return T_STRING;
740: default:
741: }
742:
743: if (isalpha(c)) { /* 識別子 */
744: return lex_symbol();
745: }
746:
747: /* 32bit 整数値 */
748: if (isdigit(c)){
749: yylval.d = lex_digit();
750: return T_INTEGER;
751: }
752: if (c == '-') {
753: c = GETC();
754: while (isspace(c) && c != '\n') {
755: c = GETC();
756: }
757: if (isdigit(c)){
758: yylval.d = - lex_digit();
759: return T_INTEGER;
760: }
761: return 0;
762: }
763:
764: c = GETC();
765: return 0;
766: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>