68ed3a7c5dc8a53dfa3489fb0fe6a82f2f133bef
[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, *r, *sepp;
9     int sepc = ',', len;
10     bool quoting = false;
11
12     opd->opdc = 0;
13     if(str == NULL) {
14         return opd;
15     }
16     p = q = strdup(str);
17     do {
18         /* オペランド数が多すぎる場合はエラー */
19         if(opd->opdc >= OPDSIZE) {
20             setcerr(117, str);    /* 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             /* 閉じ「'」がないまま文字列が終了した場合 */
33             if(*q == '\0') {
34                 setcerr(123, str);    /* unclosed quote */
35                 break;
36             }
37             q++;
38         } else {
39             sepp = q + strcspn(q, ", ");
40             sepc = *sepp;
41             *sepp = '\0';
42             if(*p == '\0') {
43                 setcerr(121, NULL);    /* cannot get operand token */
44                 break;
45             }
46             len = strlen(r = p);
47             while(*r != '\0' && (r = strstr(r, "''")) != NULL) {
48                 len--;
49                 r += 2;
50             };
51             if(len > OPDSIZE + 2) {    /* OPDSIZE + 「'」2文字分 */
52                 setcerr(118, NULL);    /* operand length is too long */
53                 break;
54             }
55             opd->opdv[(++opd->opdc)-1] = strdup(p);
56             p = q = sepp + 1;
57         }
58     } while(sepc == ',');
59     return opd;
60 }
61
62 /* 空白またはタブで区切られた1行から、トークンを取得 */
63 CMDLINE *linetok(const char *line)
64 {
65     char *tokens, *p, *sepp;
66     bool quoting = false;
67     CMDLINE *cmdl = malloc(sizeof(CMDLINE));
68
69     if(line == NULL || strlen(line) == 0) {
70         return NULL;
71     }
72     tokens = strdup(line);
73     /* コメントを削除 */
74     for(p = tokens; *p != '\0'; p++) {
75         /* 「'」で囲まれた文字列の処理。「''」は無視 */
76         if(*p == '\'' && *(p+1) != '\'' && !(p > tokens && *(p-1) == '\'')) {
77             quoting = !quoting;
78         } else if(quoting == false && *p == ';') {
79             *p = '\0';
80             break;
81         }
82     }
83     if(*tokens == '\0') {
84         return NULL;
85     }
86     p = tokens;
87     /* 行の先頭が空白またはタブの場合、ラベルは空 */
88     if((sepp = p + strcspn(p, " \t\n")) == p){
89         cmdl->label = NULL;
90     } else {        /* ラベルを取得 */
91         *sepp = '\0';
92         /* 文字列が長すぎる場合はエラー */
93         if(strlen(p) > LABELSIZE) {
94             setcerr(104, p);    /* label length is too long */
95         }
96         cmdl->label = strdup(p);
97         p = sepp + 1;
98     }
99     while(*p == ' ' || *p == '\t') {
100         p++;
101     }
102     /* 命令がない場合、終了 */
103     if(*p == '\n' || *p == '\0') {
104         /* ラベルが定義されていて命令がない場合はエラー */
105         if(cmdl->label != NULL) {
106             setcerr(105, NULL);    /* no command in the line */
107         }
108         return NULL;
109     }
110     /* 命令を取得 */
111     sepp = p + strcspn(p, " \t\n");
112     *sepp = '\0';
113     cmdl->cmd = strdup(p);
114     p = sepp + 1;
115     while(*p == ' ' || *p == '\t') {
116         p++;
117     }
118     /* オペランドを取得 */
119     cmdl->opd = malloc(sizeof(OPD));
120     /* 改行かタブまでの文字列を取得。
121        「'」で囲まれた文字列に含まれる場合があるため、空白は無視 */
122     if((sepp = p + strcspn(p, "\t\n")) > p) {
123         *sepp = '\0';
124         cmdl->opd = opdtok(p);
125     } else {
126         cmdl->opd->opdc = 0;
127     }
128     return cmdl;
129 }