依存関係を整理
[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 static int labelcnt = 0;                /* ラベル数 */
12 static LABELTAB *labels[LABELTABSIZE];  /* ラベル表 */
13
14 #ifndef UNITTEST
15 static unsigned labelhash(const char *prog, const char *label);
16
17 static int compare_adr(const void *a, const void *b);
18 #endif
19
20 /**
21  * プログラム名とラベルに対応するハッシュ値を返す
22  */
23 unsigned labelhash(const char *prog, const char *label)
24 {
25     HKEY *keys[2];
26     int i = 0;
27
28     if(prog != NULL) {
29         keys[i] = malloc_chk(sizeof(HKEY), "labelhash.key[]");
30         keys[i]->type = CHARS;
31         keys[i]->val.s = strdup_chk(prog, "labelhash.key[].val");
32     }
33     keys[i] = malloc_chk(sizeof(HKEY), "labelhash.key[]");
34     keys[i]->type = CHARS;
35     keys[i]->val.s = strdup_chk(label, "labelhash.key[].val");
36     /* ハッシュ値を返す */
37     return hash(i+1, keys, LABELTABSIZE);
38 }
39
40 /**
41  * ラベル表からアドレスを検索する
42  */
43 WORD getlabel(const char *prog, const char *label)
44 {
45     assert(label != NULL);
46     LABELTAB *np;
47
48     for(np = labels[labelhash(prog, label)]; np != NULL; np = np->next) {
49         if((prog == NULL || (np->prog != NULL && strcmp(prog, np->prog) == 0)) &&
50            strcmp(label, np->label) == 0)
51         {
52             return np->adr;
53         }
54     }
55     return 0xFFFF;
56 }
57
58 /**
59  * プログラム名、ラベル、アドレスをラベル表に追加する
60  */
61 bool addlabel(const char *prog, const char *label, WORD adr)
62 {
63     assert(label != NULL);
64     LABELTAB *np;
65     unsigned hashval;
66
67     /* 登録されたラベルを検索。すでに登録されている場合はエラー発生 */
68     if(getlabel(prog, label) != 0xFFFF) {
69         setcerr(101, label);    /* label already defined */
70         return false;
71     }
72     /* メモリを確保 */
73     np = malloc_chk(sizeof(LABELTAB), "labels.next");
74     /* プログラム名を設定 */
75     if(prog == NULL) {
76         np->prog = NULL;
77     } else {
78         np->prog = strdup_chk(prog, "labels.prog");
79     }
80     /* ラベルを設定 */
81     np->label = strdup_chk(label, "labels.label");
82     /* アドレスを設定 */
83     np->adr = adr;
84     /* ラベル数を設定 */
85     labelcnt++;
86     /* ハッシュ表へ追加 */
87     hashval = labelhash(prog, label);
88     np->next = labels[hashval];
89     labels[hashval] = np;
90     return true;
91 }
92
93 /**
94  * ラベルを比較した結果を返す
95  */
96 int compare_adr(const void *a, const void *b)
97 {
98     return (**(LABELARRAY **)a).adr - (**(LABELARRAY **)b).adr;
99 }
100
101 /**
102  * ラベル表を表示する
103  */
104 void printlabel()
105 {
106     int i, asize = 0;
107     LABELTAB *np;
108     LABELARRAY *ar[labelcnt];
109
110     for(i = 0; i < LABELTABSIZE; i++) {
111         for(np = labels[i]; np != NULL; np = np->next) {
112             assert(np->label != NULL);
113             ar[asize] = malloc_chk(sizeof(LABELARRAY), "ar[]");
114             if(np->prog == NULL) {
115                 ar[asize]->prog = NULL;
116             } else {
117                 ar[asize]->prog = strdup_chk(np->prog, "ar[].prog");
118             }
119             ar[asize]->label = strdup_chk(np->label, "ar[].label");
120             ar[asize++]->adr = np->adr;
121         }
122     }
123     qsort(ar, asize, sizeof(*ar), compare_adr);
124     for(i = 0; i < asize; i++) {
125         if(ar[i]->prog != NULL) {
126             fprintf(stdout, "%s.", ar[i]->prog);
127         }
128         fprintf(stdout, "%s ---> #%04X\n", ar[i]->label, ar[i]->adr);
129     }
130 }
131
132 /**
133  * ラベル表を解放する
134  */
135 void freelabel()
136 {
137     int i;
138     LABELTAB *np, *nq;
139
140     for(i = 0; i < LABELTABSIZE; i++) {
141         for(np = labels[i]; np != NULL; np = nq) {
142             nq = np->next;
143             if(np->prog != NULL) {
144                 free_chk(np->prog, "np.prog");
145             }
146             free_chk(np->label, "np.label");
147             free_chk(np, "np");
148         }
149     }
150 }