source: branches/help/AISC/aisc_var_ref.c

Last change on this file was 18730, checked in by westram, 3 years ago
  • remove trailing whitespace from c source.
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.5 KB
Line 
1// ================================================================
2/*                                                                  */
3//   File      : aisc_var_ref.c
4//   Purpose   :
5/*                                                                  */
6//   Institute of Microbiology (Technical University Munich)
7//   http://www.arb-home.de/
8 /*                                                                  */
9 // ================================================================
10
11#include "aisc_token.h"
12#include "aisc_inline.h"
13#include "aisc_interpreter.h"
14
15
16class TokenMatcher : virtual Noncopyable {
17    char *key;                  // NULp matches "any key"
18    char *value;                // NULp matches "any value"
19
20    char *copy_expression_part(const char *start, const char *end) {
21        if (start >= end || (end == (start+1) && start[0] == '*')) return NULp;
22        return copy_string_part(start, end);
23    }
24
25 public:
26    TokenMatcher(const char *search_expr) {
27        // search_expr is "key.value"
28        //
29        // "*.value"    searches value (regardless of key)
30        // "key.*"      searches key (regardless of value)
31        //
32        // "key"    = "key." = "key.*"
33        // ".value" = "*.value"
34
35        const char *dot = strchr(search_expr, '.');
36        if (!dot) {
37            key = strdup(search_expr);
38            value = NULp;
39        }
40        else {
41            const char *end = strchr(dot+1, 0);
42
43            key   = copy_expression_part(search_expr, dot-1);
44            value = copy_expression_part(dot+1, end-1);
45        }
46    }
47
48    ~TokenMatcher() {
49        free(key);
50        free(value);
51    }
52
53    bool matchesKeyOf(const Token *token) const {
54        return !key || strcmp(token->get_key(), key) == 0;
55    }
56    bool matchesValueOf(const Token *token) const {
57        return !value || (!token->is_block() && strcmp(value, token->get_value()) == 0);
58    }
59    bool matches(const Token *token) const {
60        return matchesKeyOf(token) && matchesValueOf(token);
61    }
62};
63
64static const Token *nextToken(const Token *tok, bool cont_in_next_list) {
65    const Token *next_token = tok->next_token();
66    if (!next_token && cont_in_next_list) {
67        const TokenList *next_list  = tok->parent_list()->next_list();
68        if (next_list) next_token = next_list->first_token();
69    }
70    return next_token;
71}
72
73static const Token *nextTokenMatching(const Token *tok, const TokenMatcher& wanted, bool cont_in_next_list) {
74    while (tok) {
75        if (wanted.matches(tok)) break;
76        tok = nextToken(tok, cont_in_next_list);
77    }
78    return tok;
79}
80
81const Token *Data::find_token(const Token *curs, const char *str, LookupScope scope) const {
82    if (!curs) {
83        const TokenListBlock *tokens = get_tokens();
84        if (!tokens) return NULp;
85        curs = tokens->first_token();
86    }
87
88    TokenMatcher  wanted(str);
89    const Token  *found = NULp;
90
91    while (curs && !found) {
92        bool cont_in_next_list = false;
93        switch (scope) {
94            case LOOKUP_LIST_OR_PARENT_LIST:
95            case LOOKUP_LIST:
96                curs              = curs->parent_list()->first_token();
97                break;
98            case LOOKUP_BLOCK:
99                curs              = curs->parent_list()->parent_block()->first_token();
100                cont_in_next_list = true;
101                break;
102            case LOOKUP_BLOCK_REST:
103                curs              = nextToken(curs, true);
104                cont_in_next_list = true;
105                break;
106        }
107
108        found = nextTokenMatching(curs, wanted, cont_in_next_list);
109
110        if (scope == LOOKUP_LIST_OR_PARENT_LIST) {
111            curs = curs->parent_block_token();
112        }
113        else {
114            curs = NULp;
115        }
116    }
117
118    return found;
119}
120
121const Token *Data::find_qualified_token(const char *str, LookupScope scope) const {
122    const Token *at = cursor;
123    if (*str == '/') {
124        at = NULp;
125        str++;
126    }
127
128    const char *slash = strchr(str, '/');
129    while (slash) {
130        char        *name  = copy_string_part(str, slash-1);
131        const Token *found = find_token(at, name, scope);
132        free(name);
133
134        if (!found || !found->is_block()) return NULp;
135
136        at = found->get_content()->first_token();
137
138        str   = slash+1;
139        slash = strchr(str, '/');
140        scope = LOOKUP_BLOCK;
141    }
142
143    return find_token(at, str, scope);
144}
145
146
147char *get_var_string(const Data& data, char *var, bool allow_missing_var) {
148    // Calculates result for an expression like '$(IDENT:fdg|"sdfg")'
149    SKIP_SPACE_LF(var);
150    int use_path = 0;
151    while (var[0] == '&') {
152        use_path++;
153        var++;
154        SKIP_SPACE_LF(var);
155    }
156
157    char *doppelpunkt = strchr(var, ':'); if (doppelpunkt) *(doppelpunkt++) = 0;
158    char *bar         = strchr(var, '|'); if (bar) *(bar++) = 0;
159
160    const char *val = Interpreter::instance->read_local(var);
161    char       *in  = NULp;
162    if (val) {
163        in = strdup(val);
164    }
165    else {
166        const Token *cur = data.find_qualified_token(var, LOOKUP_LIST_OR_PARENT_LIST);
167        if (!cur) {
168            if (!bar) {
169                if (!allow_missing_var) {
170                    const Code *at = Interpreter::instance->at();
171                    printf_error(at, "Ident '%s' not found", var);
172                }
173                return NULp;
174            }
175            return strdup(bar);
176        }
177        if (use_path) {
178            in = strdup(cur->get_key());
179            if (use_path>1) {
180                while (1) {
181                    const Token *up = cur->parent_block_token();
182                    if (!up) break;
183
184                    cur        = up;
185                    int   len  = strlen(in) + strlen(cur->get_key());
186                    char *buf1 = (char *) calloc(sizeof(char), len + 2);
187                    sprintf(buf1, "%s/%s", cur->get_key(), in);
188
189                    free(in);
190                    in = buf1;
191                }
192
193            }
194        }
195        else {
196            if (cur->is_block()) {
197                printf_error(Interpreter::instance->at(), "Ident '%s' is a hierarchical type", var);
198                return NULp;
199            }
200            else {
201                in = strdup(cur->has_value() ? cur->get_value() : "");
202            }
203        }
204    }
205
206    aisc_assert(in); // 'in' has to point to a heap copy
207
208    if (doppelpunkt) {
209        int  len = strlen(in);
210        bool err = false;
211        while (doppelpunkt && !err) {
212            char *nextdp            = strchr(doppelpunkt, ':');
213            if (nextdp) *(nextdp++) = 0;
214            if (!doppelpunkt[0]) {
215                print_error(Interpreter::instance->at(), "Ident replacement is missing an ':'");
216                err = true;
217            }
218            else {
219                bar = strchr(doppelpunkt+1, '=');
220                if (!bar) {
221                    print_error(Interpreter::instance->at(), "Ident replacement is missing an '='");
222                    err = true;
223                }
224                else {
225                    *(bar++)     = 0;
226                    int findl    = strlen(doppelpunkt);
227                    int replacel = strlen(bar);
228
229                    char *buf2;
230                    for (char *finds = strstr(in, doppelpunkt); finds; finds = strstr(buf2, doppelpunkt)) {
231                        len += replacel - findl;
232
233                        char *buf1   = (char *) calloc(sizeof(char), len + 1);
234                        int   offset = finds - in;
235
236                        memcpy(buf1, in, offset);
237                        memcpy(buf1 + offset, bar, replacel);
238
239                        buf2 = buf1 + offset + replacel;
240                        memcpy(buf2, in + offset + findl, len - replacel - offset);
241
242                        free(in);
243                        in = buf1;
244
245                        buf2 = in + offset + replacel;
246                    }
247                    doppelpunkt = nextdp;
248                }
249            }
250        }
251        if (err) {
252            free(in);
253            in = NULp;
254        }
255    }
256    return in;
257}
258
259static void dump_token_recursive(const Token *tok, FILE *out) {
260    const Token *block = tok->parent_block_token();
261    if (block) {
262        const TokenList *parent = block->parent_list();
263        if (parent) {
264            const Token *first = parent->first_token();
265            if (first) {
266                dump_token_recursive(first, out);
267                fputc('/', out);
268            }
269        }
270    }
271
272    fputc('@', out);
273    fputs(tok->get_key(), out);
274
275    if (tok->has_value()) {
276        fputc('=', out);
277        fputs(tok->get_value(), out);
278    }
279}
280
281void Data::dump_cursor_pos(FILE *out) const {
282    dump_token_recursive(cursor, out);
283}
Note: See TracBrowser for help on using the repository browser.