aa0a620e98b3033d95af87bdb73a65da7e3c5ebc
[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     CMDLINE *cmdl = malloc(sizeof(CMDLINE));
62     if(line == NULL || strlen(line) == 0) {
63         return NULL;
64     }
65     tokens = p = strdup(line);
66     /* コメントを削除 */
67     if((q = strchr(tokens, ';')) != NULL) {
68         *q = '\0';
69     }
70     if(*p == '\0') {
71         return NULL;
72     }
73     /* 行の先頭が空白またはタブの場合、ラベルは空 */
74     if((sepp = p + strcspn(p, " \t\n")) == p){
75         cmdl->label = NULL;
76     } else {        /* ラベルを取得 */
77         *sepp = '\0';
78         /* 文字列が長すぎる場合はエラー */
79         if(strlen(p) > LABELSIZE) {
80             setcerr(104, p);    /* label length is too long */
81         }
82         cmdl->label = strdup(p);
83         p = sepp + 1;
84     }
85     while(*p == ' ' || *p == '\t') {
86         p++;
87     }
88     /* 命令がない場合、終了 */
89     if(*p == '\n' || *p == '\0') {
90         /* ラベルが定義されていて命令がない場合はエラー */
91         if(cmdl->label != NULL) {
92             setcerr(105, NULL);    /* no command in the line */
93         }
94         return NULL;
95     }
96     /* 命令を取得 */
97     sepp = p + strcspn(p, " \t\n");
98     *sepp = '\0';
99     cmdl->cmd = strdup(p);
100     p = sepp + 1;
101     while(*p == ' ' || *p == '\t') {
102         p++;
103     }
104     /* オペランドを取得 */
105     cmdl->opd = malloc(sizeof(OPD));
106     /* 改行かタブまでの文字列を取得。
107        「'」で囲まれた文字列に含まれる場合があるため、空白は無視 */
108     if((sepp = p + strcspn(p, "\t\n")) > p) {
109         *sepp = '\0';
110         cmdl->opd = opdtok(p);
111     } else {
112         cmdl->opd->opdc = 0;
113     }
114     return cmdl;
115 }