d2242af96c9e6f798178801c9874d3fa75d3381e
[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
8 /**
9  * 行トークン取得のエラー定義
10  */
11 CERR cerr_linetok[] = {
12     { 104, "label length is too long" },
13     { 105, "no command in the line" },
14 };
15
16 /**
17  * オペランドトークン取得のエラー定義
18  */
19 static CERR cerr_opdtok[] = {
20     { 117, "operand too many in DC" },
21     { 118, "operand length too long" },
22     { 121, "cannot get operand token" },
23     { 123, "unclosed quote" },
24 };
25
26 /**
27  * オペランドトークン取得のエラーを追加
28  */
29 void addcerrlist_tok()
30 {
31     addcerrlist(ARRAYSIZE(cerr_linetok), cerr_linetok);
32     addcerrlist(ARRAYSIZE(cerr_opdtok), cerr_opdtok);
33 }
34
35 /**
36  * 「,」区切りの文字列から、オペランドのトークンを取得
37  */
38 OPD *opdtok(const char *str)
39 {
40     OPD *opd = malloc_chk(sizeof(OPD), "opd");
41     char *p, *q, *r, *sepp;     /* pは文字列全体の先頭位置、qはトークンの先頭位置、rは文字の位置 */
42     int sepc = ',', rcnt = 0;
43     bool quoting = false;
44
45     opd->opdc = 0;
46     if(str == NULL) {
47         return opd;
48     }
49     p = q = r = strdup_chk(str, "opdtok.p");
50     do {
51         /* オペランド数が多すぎる場合はエラー */
52         if(opd->opdc >= OPDSIZE) {
53             setcerr(117, "");    /* operand is too many */
54             break;
55         }
56         /* 先頭が等号(=)の場合 */
57         if(*r == '=') {
58             r++;
59         }
60         /* 「'」の場合 */
61         if(*r == '\'') {
62             /* 「''」以外の場合はquote値を反転 */
63             if(*(r+1) != '\'' && !(q < r && *(r-1) == '\'')) {
64                 quoting = !quoting;
65             }
66             /* 文字列の長さを数える。「'」の場合は数えない */
67             if(*(r+1) != '\'') {
68                 rcnt++;
69             }
70         }
71         if(quoting == true) {
72             /* 閉じ「'」がないまま文字列が終了した場合 */
73             if(*r == '\0') {
74                 setcerr(123, str);    /* unclosed quote */
75                 break;
76             }
77             r++;
78         } else {
79             sepp = r + strcspn(r, ", ");
80             sepc = *sepp;
81             *sepp = '\0';
82             if(*q == '\0') {
83                 setcerr(121, "");    /* cannot get operand token */
84                 break;
85             }
86             if(strlen(q) - rcnt > OPDSIZE) {
87                 setcerr(118, "");    /* operand length is too long */
88                 break;
89             }
90             opd->opdv[(++opd->opdc)-1] = strdup_chk(q, "opd.opdv[]");
91             q = r = sepp + 1;
92             rcnt = 0;
93         }
94     } while(sepc == ',');
95     FREE(p);
96     return opd;
97 }
98
99 /**
100  * 空白またはタブで区切られた1行から、トークンを取得する
101  */
102 CMDLINE *linetok(const char *line)
103 {
104     char *tokens, *p, *sepp;
105     bool quoting = false;
106     CMDLINE *cmdl = NULL;
107
108     if(*line == '\0') {
109         return NULL;
110     }
111     tokens = strdup_chk(line, "tokens");
112     /* コメントを削除 */
113     for(p = tokens; *p != '\0'; p++) {
114         /* 「'」で囲まれた文字列の処理。「''」は無視 */
115         if(*p == '\'' && *(p+1) != '\'' && !(p > tokens && *(p-1) == '\'')) {
116             quoting = !quoting;
117         } else if(quoting == false && *p == ';') {
118             *p = '\0';
119             break;
120         }
121     }
122     if(*tokens != '\n' && *tokens != '\0') {
123         p = tokens;
124         cmdl = malloc_chk(sizeof(CMDLINE), "cmdl");
125         cmdl->label = malloc_chk(sizeof(LABELSIZE + 1), "cmdl.label");
126         /* ラベルの取得。行の先頭が空白またはタブの場合、ラベルは空 */
127         if((sepp = p + strcspn(p, " \t\n")) == p){
128             cmdl->label = '\0';
129         } else {        /* ラベルを取得 */
130             *sepp = '\0';
131             /* 文字列が長すぎる場合はエラー */
132             if(strlen(p) > LABELSIZE) {
133                 setcerr(104, p);    /* label length is too long */
134             }
135             strcpy(cmdl->label, p);
136             p = sepp + 1;
137         }
138         /* ラベルと命令の間の空白をスキップ */
139         while(*p == ' ' || *p == '\t') {
140             p++;
141         }
142         /* 命令とオペランドの取得 */
143         if(*p == '\n' || *p == '\0') {        /* 命令がない場合は、終了 */
144             if(cmdl->label != '\0') {         /* ラベルが定義されていて命令がない場合はエラー */
145                 setcerr(105, "");    /* no command in the line */
146             }
147             FREE(cmdl);
148         } else {
149             /* 命令の取得 */
150             sepp = p + strcspn(p, " \t\n");
151             *sepp = '\0';
152             cmdl->cmd = strdup_chk(p, "cmdl.cmd");
153             p = sepp + 1;
154             /* 命令とオペランドの間の空白をスキップ */
155             while(*p == ' ' || *p == '\t') {
156                 p++;
157             }
158             /* 改行かタブまでの文字列を取得 */
159             /* 「'」で囲まれた文字列に含まれる場合があるため、空白は無視 */
160             if((sepp = p + strcspn(p, "\t\n")) > p) {
161                 *sepp = '\0';
162                 cmdl->opd = opdtok(p);
163             } else {
164                 cmdl->opd = malloc_chk(sizeof(OPD), "cmdl.opd");
165                 cmdl->opd->opdc = 0;
166             }
167         }
168     }
169     FREE(tokens);
170     return cmdl;
171 }