ハッシュ関数を共用体版にし、ラベルの範囲をプログラム内だけで有効に
[YACASL2.git] / src / token.c
1 #include "casl2.h"
2 #include "assemble.h"
3
4 /* 「,」区切りの文字列から、オペランドのトークンを取得 */
5 OPD *opdtok(const char *str)
6 {
7     OPD *opd = malloc(sizeof(OPD));
8     char *p, *q, *sepp;
9     int sepc = ',';
10     bool quoting = false;
11
12     opd->opdc = 0;
13     if(str == NULL || strlen(str) == 0) {
14         return opd;
15     }
16     p = q = strdup(str);
17     do {
18         /* オペランド数が多すぎる場合はエラー */
19         if(opd->opdc >= OPDSIZE) {
20             setcerr(117, NULL);    /* operand is too many */
21             break;
22         }
23         /* 先頭が「=」の場合の処理 */
24         if(*q == '=') {
25             q++;
26         }
27         /* 「'」で囲まれた文字列の処理。「''」は無視 */
28         if(*q == '\'' && *(q+1) != '\'' && !(p < q && *(q-1) == '\'')) {
29             quoting = !quoting;
30         }
31         if(quoting == true) {
32             q++;
33         } else {
34             sepp = q + strcspn(q, ", ");
35             sepc = *sepp;
36             *sepp = '\0';
37             if(strlen(p) == 0) {
38                 setcerr(121, NULL);    /* cannot get operand token */
39                 break;
40             }
41             if(strlen(p) > OPDSIZE + 2) {    /* OPDSIZE + 「'」2文字分 */
42                 setcerr(118, p);    /* operand length is too long */
43                 break;
44             }
45             opd->opdv[(++opd->opdc)-1] = strdup(p);
46             p = q = sepp + 1;
47         }
48     } while(sepc == ',');
49     return opd;
50 }
51
52 /* 空白またはタブで区切られた1行から、トークンを取得 */
53 CMDLINE *linetok(const char *line)
54 {
55     char *tokens, *p, *q, *sepp;
56     CMDLINE *cmdl = malloc(sizeof(CMDLINE));
57     if(line == NULL || strlen(line) == 0) {
58         return NULL;
59     }
60     tokens = p = strdup(line);
61     /* コメントを削除 */
62     if((q = strchr(tokens, ';')) != NULL) {
63         *q = '\0';
64     }
65     if(*p == '\0') {
66         return NULL;
67     }
68     /* 行の先頭が空白またはタブの場合、ラベルは空 */
69     if((sepp = p + strcspn(p, " \t\n")) == p){
70         cmdl->label = NULL;
71     } else {        /* ラベルを取得 */
72         *sepp = '\0';
73         /* 文字列が長すぎる場合はエラー */
74         if(strlen(p) > LABELSIZE) {
75             setcerr(104, p);    /* label length is too long */
76         }
77         cmdl->label = strdup(p);
78         p = sepp + 1;
79     }
80     while(*p == ' ' || *p == '\t') {
81         p++;
82     }
83     /* 命令がない場合、終了 */
84     if(*p == '\n' || *p == '\0') {
85         /* ラベルが定義されていて命令がない場合はエラー */
86         if(cmdl->label != NULL) {
87             setcerr(105, NULL);    /* no command in the line */
88         }
89         return NULL;
90     }
91     /* 命令を取得 */
92     sepp = p + strcspn(p, " \t\n");
93     *sepp = '\0';
94     cmdl->cmd = strdup(p);
95     p = sepp + 1;
96     while(*p == ' ' || *p == '\t') {
97         p++;
98     }
99     /* オペランドを取得 */
100     cmdl->opd = malloc(sizeof(OPD));
101     /* 改行かタブまでの文字列を取得。
102        「'」で囲まれた文字列に含まれる場合があるため、空白は無視 */
103     if((sepp = p + strcspn(p, "\t\n")) > p) {
104         *sepp = '\0';
105         cmdl->opd = opdtok(p);
106     } else {
107         cmdl->opd->opdc = 0;
108     }
109     return cmdl;
110 }