ラベル表の構造を整理
[YACASL2.git] / src / label.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <assert.h>
5
6 #include "cerr.h"
7 #include "cmem.h"
8 #include "hash.h"
9 #include "assemble.h"
10
11 /**
12  * ラベルのハッシュ値をセットしたキーを返す
13  *
14  * @return ハッシュ値をセットしたキー
15  *
16  * @param value 値
17  */
18 HKEY *label_hashkey(const char *value);
19
20 /**
21  * プログラム名とラベルに対応するハッシュ値を返す
22  *
23  * @return ハッシュ値
24  *
25  * @param prog プログラム名
26  * @param label ラベル
27  */
28 unsigned labelhash(const char *prog, const char *label);
29
30 /**
31  * ラベルを比較した結果を返す。qsort内で使われる関数
32  *
33  * @return ラベルが同一の場合は0、異なる場合は0以外
34  *
35  * @param *a ラベルa
36  * @param *b ラベルb
37  */
38 int compare_adr(const void *a, const void *b);
39
40 /**
41  * @brief ラベル数
42  */
43 static int labelcnt = 0;
44
45 /**
46  * @brief ラベル表
47  */
48 static LABELTAB *labels[LABELTABSIZE];
49
50 /**
51  * @brief ラベルのエラー
52  */
53 static CERR cerr_label[] = {
54     { 101, "label already defined" },
55     { 102, "label table is full" },
56     { 103, "label not found" },
57 };
58
59 HKEY *label_hashkey(const char *value) {
60     HKEY *key;
61
62     key = malloc_chk(sizeof(HKEY), "label_hashkey");
63     key->type = CHARS;
64     key->val.s = strdup_chk(value, "label_hashkey.value");
65     return key;
66 }
67
68 unsigned labelhash(const char *prog, const char *label)
69 {
70     HKEY *keys[2];
71     int i = 0, j;
72     unsigned h;
73
74     if(*prog != '\0') {
75         keys[i++] = label_hashkey(prog);
76     }
77     keys[i] = label_hashkey(label);
78     h = hash(i+1, keys, LABELTABSIZE);
79     for(j = 0; j < i + 1; j++) {
80         FREE(keys[j]->val.s);
81         FREE(keys[j]);
82     }
83     return h;
84 }
85
86 int compare_adr(const void *a, const void *b)
87 {
88     return (**(LABELARRAY **)a).adr - (**(LABELARRAY **)b).adr;
89 }
90
91 /* assemble.hで定義された関数群 */
92 void addcerrlist_label()
93 {
94     addcerrlist(ARRAYSIZE(cerr_label), cerr_label);
95 }
96
97 WORD getlabel(const char *prog, const char *label)
98 {
99     assert(prog != NULL && label != NULL);
100     LABELTAB *p;
101     LABELARRAY *l;
102
103     for(p = labels[labelhash(prog, label)]; p != NULL; p = p->next) {
104         l = p->label;
105         if((*prog == '\0' || (strcmp(prog, l->prog) == 0)) &&
106            strcmp(label, l->label) == 0)
107         {
108             return l->adr;
109         }
110     }
111     return 0xFFFF;
112 }
113
114 bool addlabel(const char *prog, const char *label, WORD adr)
115 {
116     assert(label != NULL);
117     LABELTAB *p;
118     LABELARRAY *l;
119     unsigned hashval;
120
121     /* 登録されたラベルを検索。すでに登録されている場合はエラー発生 */
122     if(getlabel(prog, label) != 0xFFFF) {
123         setcerr(101, label);    /* label already defined */
124         return false;
125     }
126     /* メモリを確保 */
127     p = malloc_chk(sizeof(LABELTAB), "labels.next");
128     l = p->label = malloc_chk(sizeof(LABELARRAY), "labels.label");
129     /* プログラム名を設定 */
130     l->prog = strdup_chk(prog, "label.prog");
131     /* ラベルを設定 */
132     l->label = strdup_chk(label, "label.label");
133     /* アドレスを設定 */
134     l->adr = adr;
135     /* ラベル数を設定 */
136     labelcnt++;
137     /* ハッシュ表へ追加 */
138     hashval = labelhash(prog, label);
139     p->next = labels[hashval];
140     labels[hashval] = p;
141     return true;
142 }
143
144 void printlabel()
145 {
146     int i, s = 0;
147     LABELTAB *p;
148     LABELARRAY **l;
149
150     l = calloc_chk(labelcnt, sizeof(LABELARRAY **), "labels");
151     for(i = 0; i < LABELTABSIZE; i++) {
152         for(p = labels[i]; p != NULL; p = p->next) {
153             assert(p->label != NULL);
154             l[s++] = p->label;
155         }
156     }
157     qsort(l, s, sizeof(*l), compare_adr);
158     for(i = 0; i < s; i++) {
159         if(*(l[i]->prog) != '\0') {
160             fprintf(stdout, "%s.", l[i]->prog);
161         }
162         fprintf(stdout, "%s ---> #%04X\n", l[i]->label, l[i]->adr);
163     }
164     FREE(l);
165 }
166
167 void freelabel()
168 {
169     int i;
170     LABELTAB *p, *q;
171
172     for(i = 0; i < LABELTABSIZE; i++) {
173         for(p = labels[i]; p != NULL; p = q) {
174             q = p->next;
175             FREE(p->label->prog);
176             FREE(p->label->label);
177             FREE(p->label);
178             FREE(p);
179         }
180     }
181 }