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