3972d517d4d4ec1fac7ec9a213663518f57375a1
[YACASL2.git] / src / token.c
1 #include <stdio.h>
2 #include <string.h>
3 #include "cerr.h"
4 #include "cmem.h"
5 #include "assemble.h"
6
7 #ifndef UNITTEST
8 static OPD *opdtok(const char *str);
9 #endif
10
11 /* 「,」区切りの文字列から、オペランドのトークンを取得 */
12 OPD *opdtok(const char *str)
13 {
14     OPD *opd = malloc_chk(sizeof(OPD), "opd");
15     char *p, *q, *r, *sepp;     /* pは文字列全体の先頭位置、qはトークンの先頭位置、rは文字の位置 */
16     int sepc = ',', rcnt = 0;
17     bool quoting = false;
18
19     opd->opdc = 0;
20     if(str == NULL) {
21         return opd;
22     }
23     p = q = r = strdup_chk(str, "opdtopk.p");
24     do {
25         /* オペランド数が多すぎる場合はエラー */
26         if(opd->opdc >= OPDSIZE) {
27             setcerr(117, NULL);    /* operand is too many */
28             break;
29         }
30         /* 先頭が「=」の場合 */
31         if(*r == '=') {
32             r++;
33         }
34         /* 「'」の場合 */
35         if(*r == '\'') {
36             /* 「''」以外の場合はquote値を反転 */
37             if(*(r+1) != '\'' && !(q < r && *(r-1) == '\'')) {
38                 quoting = !quoting;
39             }
40             /* 文字列の長さを数える。「'」の場合は数えない */
41             if(*(r+1) != '\'') {
42                 rcnt++;
43             }
44         }
45         if(quoting == true) {
46             /* 閉じ「'」がないまま文字列が終了した場合 */
47             if(*r == '\0') {
48                 setcerr(123, str);    /* unclosed quote */
49                 break;
50             }
51             r++;
52         } else {
53             sepp = r + strcspn(r, ", ");
54             sepc = *sepp;
55             *sepp = '\0';
56             if(*q == '\0') {
57                 setcerr(121, NULL);    /* cannot get operand token */
58                 break;
59             }
60             if(strlen(q) - rcnt > OPDSIZE) {
61                 setcerr(118, NULL);    /* operand length is too long */
62                 break;
63             }
64             opd->opdv[(++opd->opdc)-1] = strdup_chk(q, "opd.opdv[]");
65             q = r = sepp + 1;
66             rcnt = 0;
67         }
68     } while(sepc == ',');
69     free_chk(p, "opdtok.p");
70     return opd;
71 }
72
73 /* 空白またはタブで区切られた1行から、トークンを取得 */
74 CMDLINE *linetok(const char *line)
75 {
76     char *tokens, *p, *sepp;
77     bool quoting = false;
78     CMDLINE *cmdl = malloc_chk(sizeof(CMDLINE), "cmdl");
79
80     if(line == NULL || strlen(line) == 0) {
81         return NULL;
82     }
83     tokens = strdup_chk(line, "tokens");
84     /* コメントを削除 */
85     for(p = tokens; *p != '\0'; p++) {
86         /* 「'」で囲まれた文字列の処理。「''」は無視 */
87         if(*p == '\'' && *(p+1) != '\'' && !(p > tokens && *(p-1) == '\'')) {
88             quoting = !quoting;
89         } else if(quoting == false && *p == ';') {
90             *p = '\0';
91             break;
92         }
93     }
94     if(*tokens == '\0') {
95         return NULL;
96     }
97     p = tokens;
98     /* 行の先頭が空白またはタブの場合、ラベルは空 */
99     if((sepp = p + strcspn(p, " \t\n")) == p){
100         cmdl->label = NULL;
101     } else {        /* ラベルを取得 */
102         *sepp = '\0';
103         /* 文字列が長すぎる場合はエラー */
104         if(strlen(p) > LABELSIZE) {
105             setcerr(104, p);    /* label length is too long */
106         }
107         cmdl->label = strdup_chk(p, "cmdl.label");
108         p = sepp + 1;
109     }
110     while(*p == ' ' || *p == '\t') {
111         p++;
112     }
113     /* 命令がない場合、終了 */
114     if(*p == '\n' || *p == '\0') {
115         /* ラベルが定義されていて命令がない場合はエラー */
116         if(cmdl->label != NULL) {
117             setcerr(105, NULL);    /* no command in the line */
118         }
119         return NULL;
120     }
121     /* 命令を取得 */
122     sepp = p + strcspn(p, " \t\n");
123     *sepp = '\0';
124     cmdl->cmd = strdup_chk(p, "cmdl.cmd");
125     p = sepp + 1;
126     while(*p == ' ' || *p == '\t') {
127         p++;
128     }
129     /* オペランドを取得 */
130     cmdl->opd = malloc_chk(sizeof(OPD), "cmdl.opd");
131     /* 改行かタブまでの文字列を取得。
132        「'」で囲まれた文字列に含まれる場合があるため、空白は無視 */
133     if((sepp = p + strcspn(p, "\t\n")) > p) {
134         *sepp = '\0';
135         cmdl->opd = opdtok(p);
136     } else {
137         cmdl->opd->opdc = 0;
138     }
139     return cmdl;
140 }