commit de8d436
shrub
·
2026-04-07 22:06:53 +0000 UTC
parent bcdf49f
split files
5 files changed,
+621,
-573
M
Makefile
+1,
-1
1@@ -1,5 +1,5 @@
2 BIN = shin
3-SRCS = main.c shinobi.c
4+SRCS = main.c parse.c eval.c util.c
5 FMTSRCS = $(SRCS) shinobi.h
6 OBJS = $(SRCS:.c=.o)
7
A
eval.c
+540,
-0
1@@ -0,0 +1,540 @@
2+#include "shinobi.h"
3+#include "internal.h"
4+
5+#include <ctype.h>
6+#include <stddef.h>
7+#include <stdio.h>
8+#include <stdlib.h>
9+#include <string.h>
10+
11+/*
12+ * eval does the second pass over the built ast
13+ * seed builtins like CC and so on
14+ * apply assignment semantics
15+ * expand plain var refs and simple substitution refs
16+ * execute conditionals and flatten the chosen branch
17+ *
18+ * right now only a small subset of gmake syntax is handled.
19+ */
20+
21+struct Var {
22+ char *name;
23+ char *val;
24+ int simple;
25+};
26+
27+struct Env {
28+ struct Var *v;
29+ size_t n;
30+};
31+
32+static struct Var *
33+findvar(struct Env *env, const char *name)
34+{
35+ size_t i;
36+
37+ for (i = 0; i < env->n; i++) {
38+ if (strcmp(env->v[i].name, name) == 0)
39+ return &env->v[i];
40+ }
41+ return 0;
42+}
43+
44+static char *
45+cat2(const char *a, const char *b)
46+{
47+ size_t na, nb;
48+ char *s;
49+
50+ na = strlen(a);
51+ nb = strlen(b);
52+ s = xmalloc(na + nb + 1);
53+ memcpy(s, a, na);
54+ memcpy(s + na, b, nb);
55+ s[na + nb] = 0;
56+ return s;
57+}
58+
59+static int
60+isplainvar(const char *s, size_t n)
61+{
62+ size_t i;
63+
64+ if (!n)
65+ return 0;
66+ for (i = 0; i < n; i++) {
67+ if (!(isalnum((unsigned char)s[i]) || s[i] == '_'))
68+ return 0;
69+ }
70+ return 1;
71+}
72+
73+static char *
74+substword(const char *word, size_t n, const char *from, const char *to)
75+{
76+ size_t nfrom, nto;
77+ const char *pct;
78+ char *out;
79+
80+ nfrom = strlen(from);
81+ nto = strlen(to);
82+ pct = strchr(from, '%');
83+ if (!pct) {
84+ if (n < nfrom || memcmp(word + n - nfrom, from, nfrom) != 0)
85+ return xstrndup(word, n);
86+ out = xmalloc(n - nfrom + nto + 1);
87+ memcpy(out, word, n - nfrom);
88+ memcpy(out + n - nfrom, to, nto);
89+ out[n - nfrom + nto] = 0;
90+ return out;
91+ }
92+ {
93+ size_t pre, suf, stem;
94+ const char *tpct;
95+
96+ pre = (size_t)(pct - from);
97+ suf = nfrom - pre - 1;
98+ if (n < pre + suf)
99+ return xstrndup(word, n);
100+ if (memcmp(word, from, pre) != 0 || memcmp(word + n - suf, pct + 1, suf) != 0)
101+ return xstrndup(word, n);
102+ stem = n - pre - suf;
103+ tpct = strchr(to, '%');
104+ if (!tpct) {
105+ out = xstrdup(to);
106+ return out;
107+ }
108+ {
109+ size_t tpre, tsuf;
110+
111+ tpre = (size_t)(tpct - to);
112+ tsuf = nto - tpre - 1;
113+ out = xmalloc(tpre + stem + tsuf + 1);
114+ memcpy(out, to, tpre);
115+ memcpy(out + tpre, word + pre, stem);
116+ memcpy(out + tpre + stem, tpct + 1, tsuf);
117+ out[tpre + stem + tsuf] = 0;
118+ return out;
119+ }
120+ }
121+}
122+
123+static char *
124+substval(const char *val, const char *from, const char *to)
125+{
126+ size_t i, j, n, cap, len, wn;
127+ char *out, *part;
128+
129+ n = strlen(val);
130+ cap = n + 1;
131+ len = 0;
132+ out = xmalloc(cap);
133+ for (i = 0; i < n;) {
134+ if (isspace((unsigned char)val[i])) {
135+ if (len + 2 > cap) {
136+ cap *= 2;
137+ out = xrealloc(out, cap);
138+ }
139+ out[len++] = val[i++];
140+ continue;
141+ }
142+ j = i;
143+ while (j < n && !isspace((unsigned char)val[j]))
144+ j++;
145+ part = substword(val + i, j - i, from, to);
146+ wn = strlen(part);
147+ if (len + wn + 1 > cap) {
148+ cap = len + wn + 1;
149+ out = xrealloc(out, cap);
150+ }
151+ memcpy(out + len, part, wn);
152+ len += wn;
153+ free(part);
154+ i = j;
155+ }
156+ out[len] = 0;
157+ return out;
158+}
159+
160+static int
161+issubstref(const char *s, size_t n, size_t *colon, size_t *eq)
162+{
163+ size_t i;
164+
165+ for (i = 0; i < n; i++) {
166+ if (s[i] == ':') {
167+ *colon = i;
168+ break;
169+ }
170+ if (!(isalnum((unsigned char)s[i]) || s[i] == '_'))
171+ return 0;
172+ }
173+ if (i == 0 || i >= n)
174+ return 0;
175+ for (i = *colon + 1; i < n; i++) {
176+ if (s[i] == '=') {
177+ *eq = i;
178+ return i > *colon + 1;
179+ }
180+ }
181+ return 0;
182+}
183+
184+static char *
185+expandstr(struct Env *env, const char *s)
186+{
187+ size_t i, j, k, n, cap, len, inner, start, colon, eq;
188+ char close;
189+ char *out, *name, *val, *from, *to;
190+ struct Var *v;
191+
192+ n = strlen(s);
193+ cap = n + 1;
194+ len = 0;
195+ out = xmalloc(cap);
196+ for (i = 0; i < n; i++) {
197+ if (s[i] != '$' || i + 1 >= n || (s[i + 1] != '(' && s[i + 1] != '{')) {
198+ if (len + 2 > cap) {
199+ cap *= 2;
200+ out = xrealloc(out, cap);
201+ }
202+ out[len++] = s[i];
203+ continue;
204+ }
205+ close = s[i + 1] == '(' ? ')' : '}';
206+ start = i;
207+ j = i + 2;
208+ inner = 1;
209+ while (j < n && inner) {
210+ if (s[j] == '$' && j + 1 < n && (s[j + 1] == '(' || s[j + 1] == '{')) {
211+ inner++;
212+ j += 2;
213+ continue;
214+ }
215+ if (s[j] == close)
216+ inner--;
217+ j++;
218+ }
219+ if (inner) {
220+ if (len + (n - start) + 1 > cap) {
221+ cap = len + (n - start) + 1;
222+ out = xrealloc(out, cap);
223+ }
224+ memcpy(out + len, s + start, n - start);
225+ len += n - start;
226+ break;
227+ }
228+ if (isplainvar(s + i + 2, j - i - 3)) {
229+ name = xstrndup(s + i + 2, j - i - 3);
230+ v = findvar(env, name);
231+ free(name);
232+ val = v ? expandstr(env, v->val) : xstrdup("");
233+ k = strlen(val);
234+ if (len + k + 1 > cap) {
235+ cap = len + k + 1;
236+ out = xrealloc(out, cap);
237+ }
238+ memcpy(out + len, val, k);
239+ len += k;
240+ free(val);
241+ } else if (issubstref(s + i + 2, j - i - 3, &colon, &eq)) {
242+ name = xstrndup(s + i + 2, colon);
243+ from = xstrndup(s + i + 2 + colon + 1, eq - colon - 1);
244+ to = xstrndup(s + i + 2 + eq + 1, j - i - 4 - eq);
245+ v = findvar(env, name);
246+ free(name);
247+ if (v) {
248+ char *base;
249+
250+ base = expandstr(env, v->val);
251+ val = substval(base, from, to);
252+ free(base);
253+ } else {
254+ val = xstrdup("");
255+ }
256+ free(from);
257+ free(to);
258+ k = strlen(val);
259+ if (len + k + 1 > cap) {
260+ cap = len + k + 1;
261+ out = xrealloc(out, cap);
262+ }
263+ memcpy(out + len, val, k);
264+ len += k;
265+ free(val);
266+ } else {
267+ k = j - start;
268+ if (len + k + 1 > cap) {
269+ cap = len + k + 1;
270+ out = xrealloc(out, cap);
271+ }
272+ memcpy(out + len, s + start, k);
273+ len += k;
274+ }
275+ i = j - 1;
276+ }
277+ out[len] = 0;
278+ return out;
279+}
280+
281+static void
282+setvar(struct Env *env, const char *name, char *val, int simple)
283+{
284+ struct Var *v;
285+
286+ v = findvar(env, name);
287+ if (v) {
288+ free(v->val);
289+ v->val = val;
290+ v->simple = simple;
291+ return;
292+ }
293+ env->v = xrealloc(env->v, (env->n + 1) * sizeof(env->v[0]));
294+ env->v[env->n].name = xstrdup(name);
295+ env->v[env->n].val = val;
296+ env->v[env->n].simple = simple;
297+ env->n++;
298+}
299+
300+static void
301+seedenv(struct Env *env)
302+{
303+ setvar(env, "CC", xstrdup("cc"), 1);
304+ setvar(env, "CXX", xstrdup("c++"), 1);
305+ setvar(env, "CPP", xstrdup("$(CC) -E"), 0);
306+ setvar(env, "AR", xstrdup("ar"), 1);
307+ setvar(env, "ARFLAGS", xstrdup("-rv"), 1);
308+ setvar(env, "AS", xstrdup("as"), 1);
309+ setvar(env, "LD", xstrdup("ld"), 1);
310+ setvar(env, "LEX", xstrdup("lex"), 1);
311+ setvar(env, "YACC", xstrdup("yacc"), 1);
312+ setvar(env, "SHELL", xstrdup("/bin/sh"), 1);
313+}
314+
315+static void
316+freeenv(struct Env *env)
317+{
318+ size_t i;
319+
320+ for (i = 0; i < env->n; i++) {
321+ free(env->v[i].name);
322+ free(env->v[i].val);
323+ }
324+ free(env->v);
325+ env->v = 0;
326+ env->n = 0;
327+}
328+
329+static void
330+evalassign(struct Env *env, const struct AssignNode *in)
331+{
332+ struct Var *v;
333+ char *rhs, *joined;
334+
335+ if (in->tspec)
336+ return;
337+ switch (in->op) {
338+ case ASSIGN_EQ:
339+ setvar(env, in->lhs, xstrdup(in->rhs), 0);
340+ break;
341+ case ASSIGN_COLON_EQ:
342+ setvar(env, in->lhs, expandstr(env, in->rhs), 1);
343+ break;
344+ case ASSIGN_QMARK_EQ:
345+ if (!findvar(env, in->lhs))
346+ setvar(env, in->lhs, xstrdup(in->rhs), 0);
347+ break;
348+ case ASSIGN_PLUS_EQ:
349+ v = findvar(env, in->lhs);
350+ if (!v) {
351+ setvar(env, in->lhs, xstrdup(in->rhs), 0);
352+ break;
353+ }
354+ rhs = v->simple ? expandstr(env, in->rhs) : xstrdup(in->rhs);
355+ joined = cat2(v->val, rhs);
356+ free(rhs);
357+ free(v->val);
358+ v->val = joined;
359+ break;
360+ case ASSIGN_BANG_EQ:
361+ setvar(env, in->lhs, expandstr(env, in->rhs), 1);
362+ break;
363+ }
364+}
365+
366+static int
367+testcond(struct Env *env, const struct CondNode *cond)
368+{
369+ char *a, *b;
370+ int ok;
371+
372+ a = cond->arg1 ? expandstr(env, cond->arg1) : xstrdup("");
373+ b = cond->arg2 ? expandstr(env, cond->arg2) : xstrdup("");
374+ ok = strcmp(a, b) == 0;
375+ free(a);
376+ free(b);
377+ if (cond->kind == COND_IFNEQ)
378+ ok = !ok;
379+ return ok;
380+}
381+
382+static void
383+copywords(struct StrList *out, const struct StrList *in, struct Env *env)
384+{
385+ size_t i;
386+
387+ memset(out, 0, sizeof(*out));
388+ for (i = 0; i < in->n; i++) {
389+ out->v = xrealloc(out->v, (out->n + 1) * sizeof(out->v[0]));
390+ out->v[out->n++] = expandstr(env, in->v[i]);
391+ }
392+}
393+
394+static void
395+copyrecipes(struct RecipeList *out, const struct RecipeList *in, struct Env *env)
396+{
397+ size_t i;
398+
399+ memset(out, 0, sizeof(*out));
400+ for (i = 0; i < in->n; i++) {
401+ out->v = xrealloc(out->v, (out->n + 1) * sizeof(out->v[0]));
402+ out->v[out->n++] = expandstr(env, in->v[i]);
403+ }
404+}
405+
406+static int
407+evalnodes(const struct NodeList *in, struct NodeList *out, struct Env *env)
408+{
409+ size_t i;
410+
411+ memset(out, 0, sizeof(*out));
412+ for (i = 0; i < in->n; i++) {
413+ const struct Node *src;
414+ struct Node node;
415+
416+ src = &in->v[i];
417+ memset(&node, 0, sizeof(node));
418+ node.kind = src->kind;
419+ node.loc = src->loc;
420+ switch (src->kind) {
421+ case NODE_BLANK:
422+ break;
423+ case NODE_COMMENT:
424+ case NODE_RAW:
425+ node.data.raw.text = xstrdup(src->data.raw.text);
426+ break;
427+ case NODE_INCLUDE:
428+ node.data.include.optional = src->data.include.optional;
429+ node.data.include.path = expandstr(env, src->data.include.path);
430+ break;
431+ case NODE_COND:
432+ if (testcond(env, &src->data.cond)) {
433+ if (evalnodes(&src->data.cond.thenpart, out, env) < 0)
434+ return -1;
435+ } else {
436+ if (evalnodes(&src->data.cond.elsepart, out, env) < 0)
437+ return -1;
438+ }
439+ continue;
440+ case NODE_ASSIGN:
441+ node.data.assign.lhs = xstrdup(src->data.assign.lhs);
442+ node.data.assign.op = src->data.assign.op;
443+ node.data.assign.tspec = src->data.assign.tspec;
444+ if (src->data.assign.op == ASSIGN_COLON_EQ || src->data.assign.op == ASSIGN_BANG_EQ)
445+ node.data.assign.rhs = expandstr(env, src->data.assign.rhs);
446+ else
447+ node.data.assign.rhs = xstrdup(src->data.assign.rhs);
448+ copywords(&node.data.assign.targets, &src->data.assign.targets, env);
449+ evalassign(env, &src->data.assign);
450+ break;
451+ case NODE_RULE:
452+ copywords(&node.data.rule.targets, &src->data.rule.targets, env);
453+ copywords(&node.data.rule.prereqs, &src->data.rule.prereqs, env);
454+ copywords(&node.data.rule.order_only, &src->data.rule.order_only, env);
455+ copyrecipes(&node.data.rule.recipes, &src->data.rule.recipes, env);
456+ break;
457+ }
458+ addnode(out, node);
459+ }
460+ return 0;
461+}
462+
463+int
464+eval(const struct Ast *ast, struct Ast *out)
465+{
466+ struct Env env;
467+ int rc;
468+
469+ memset(&env, 0, sizeof(env));
470+ seedenv(&env);
471+ rc = evalnodes((const struct NodeList *)ast, (struct NodeList *)out, &env);
472+ freeenv(&env);
473+ return rc;
474+}
475+
476+static void
477+freestrs(struct StrList *list)
478+{
479+ size_t i;
480+
481+ for (i = 0; i < list->n; i++)
482+ free(list->v[i]);
483+ free(list->v);
484+}
485+
486+static void
487+freerec(struct RecipeList *list)
488+{
489+ size_t i;
490+
491+ for (i = 0; i < list->n; i++)
492+ free(list->v[i]);
493+ free(list->v);
494+}
495+
496+static void
497+freenodes(struct NodeList *list)
498+{
499+ size_t i;
500+
501+ for (i = 0; i < list->n; i++) {
502+ switch (list->v[i].kind) {
503+ case NODE_COMMENT:
504+ case NODE_RAW:
505+ free(list->v[i].data.raw.text);
506+ break;
507+ case NODE_ASSIGN:
508+ free(list->v[i].data.assign.lhs);
509+ free(list->v[i].data.assign.rhs);
510+ freestrs(&list->v[i].data.assign.targets);
511+ break;
512+ case NODE_RULE:
513+ freestrs(&list->v[i].data.rule.targets);
514+ freestrs(&list->v[i].data.rule.prereqs);
515+ freestrs(&list->v[i].data.rule.order_only);
516+ freerec(&list->v[i].data.rule.recipes);
517+ break;
518+ case NODE_INCLUDE:
519+ free(list->v[i].data.include.path);
520+ break;
521+ case NODE_COND:
522+ free(list->v[i].data.cond.arg1);
523+ free(list->v[i].data.cond.arg2);
524+ free(list->v[i].data.cond.raw);
525+ freenodes(&list->v[i].data.cond.thenpart);
526+ freenodes(&list->v[i].data.cond.elsepart);
527+ break;
528+ case NODE_BLANK:
529+ break;
530+ }
531+ }
532+ free(list->v);
533+ list->v = 0;
534+ list->n = 0;
535+}
536+
537+void
538+freeast(struct Ast *ast)
539+{
540+ freenodes((struct NodeList *)ast);
541+}
+12,
-0
1@@ -0,0 +1,12 @@
2+#ifndef INTERNAL_H
3+#define INTERNAL_H
4+
5+#include "shinobi.h"
6+
7+void *xmalloc(size_t n);
8+void *xrealloc(void *p, size_t n);
9+char *xstrndup(const char *s, size_t n);
10+char *xstrdup(const char *s);
11+void addnode(struct NodeList *list, struct Node node);
12+
13+#endif
R shinobi.c =>
parse.c
+11,
-572
1@@ -1,4 +1,5 @@
2 #include "shinobi.h"
3+#include "internal.h"
4
5 #include <ctype.h>
6 #include <stddef.h>
7@@ -6,6 +7,16 @@
8 #include <stdlib.h>
9 #include <string.h>
10
11+/*
12+ * parse owns the first bit of the pipeline:
13+ * preproc reads file, joins \ newlines, strips comments,
14+ * and resolves includes, passes that to buildast.
15+ * buildast parses that gnu make syntax into nodes.
16+ *
17+ * this is only abt syntax. we dont eval variables or
18+ * execute conditional branches.
19+ */
20+
21 struct AssignScan {
22 size_t pos;
23 size_t len;
24@@ -18,67 +29,6 @@ struct Inc {
25 size_t n;
26 };
27
28-struct Var {
29- char *name;
30- char *val;
31- int simple;
32-};
33-
34-struct Env {
35- struct Var *v;
36- size_t n;
37-};
38-
39-static void *
40-xmalloc(size_t n)
41-{
42- void *p;
43-
44- p = malloc(n ? n : 1);
45- if (!p) {
46- fprintf(stderr, "out of memory\n");
47- exit(1);
48- }
49- return p;
50-}
51-
52-static void *
53-xrealloc(void *p, size_t n)
54-{
55- void *q;
56-
57- q = realloc(p, n ? n : 1);
58- if (!q) {
59- fprintf(stderr, "out of memory\n");
60- exit(1);
61- }
62- return q;
63-}
64-
65-static char *
66-xstrndup(const char *s, size_t n)
67-{
68- char *p;
69-
70- p = xmalloc(n + 1);
71- memcpy(p, s, n);
72- p[n] = 0;
73- return p;
74-}
75-
76-static char *
77-xstrdup(const char *s)
78-{
79- return xstrndup(s, strlen(s));
80-}
81-
82-static void
83-addnode(struct NodeList *list, struct Node node)
84-{
85- list->v = xrealloc(list->v, (list->n + 1) * sizeof(list->v[0]));
86- list->v[list->n++] = node;
87-}
88-
89 static char *
90 trimdup(const char *s, size_t n)
91 {
92@@ -816,514 +766,3 @@ parse(const char *path, const char *src, struct Ast *ast)
93 freepre(&pre);
94 return rc;
95 }
96-
97-static struct Var *
98-findvar(struct Env *env, const char *name)
99-{
100- size_t i;
101-
102- for (i = 0; i < env->n; i++) {
103- if (strcmp(env->v[i].name, name) == 0)
104- return &env->v[i];
105- }
106- return 0;
107-}
108-
109-static char *
110-cat2(const char *a, const char *b)
111-{
112- size_t na, nb;
113- char *s;
114-
115- na = strlen(a);
116- nb = strlen(b);
117- s = xmalloc(na + nb + 1);
118- memcpy(s, a, na);
119- memcpy(s + na, b, nb);
120- s[na + nb] = 0;
121- return s;
122-}
123-
124-static int
125-isplainvar(const char *s, size_t n)
126-{
127- size_t i;
128-
129- if (!n)
130- return 0;
131- for (i = 0; i < n; i++) {
132- if (!(isalnum((unsigned char)s[i]) || s[i] == '_'))
133- return 0;
134- }
135- return 1;
136-}
137-
138-static char *
139-substword(const char *word, size_t n, const char *from, const char *to)
140-{
141- size_t nfrom, nto;
142- const char *pct;
143- char *out;
144-
145- nfrom = strlen(from);
146- nto = strlen(to);
147- pct = strchr(from, '%');
148- if (!pct) {
149- if (n < nfrom || memcmp(word + n - nfrom, from, nfrom) != 0)
150- return xstrndup(word, n);
151- out = xmalloc(n - nfrom + nto + 1);
152- memcpy(out, word, n - nfrom);
153- memcpy(out + n - nfrom, to, nto);
154- out[n - nfrom + nto] = 0;
155- return out;
156- }
157- {
158- size_t pre, suf, stem;
159- const char *tpct;
160-
161- pre = (size_t)(pct - from);
162- suf = nfrom - pre - 1;
163- if (n < pre + suf)
164- return xstrndup(word, n);
165- if (memcmp(word, from, pre) != 0 || memcmp(word + n - suf, pct + 1, suf) != 0)
166- return xstrndup(word, n);
167- stem = n - pre - suf;
168- tpct = strchr(to, '%');
169- if (!tpct) {
170- out = xstrdup(to);
171- return out;
172- }
173- {
174- size_t tpre, tsuf;
175-
176- tpre = (size_t)(tpct - to);
177- tsuf = nto - tpre - 1;
178- out = xmalloc(tpre + stem + tsuf + 1);
179- memcpy(out, to, tpre);
180- memcpy(out + tpre, word + pre, stem);
181- memcpy(out + tpre + stem, tpct + 1, tsuf);
182- out[tpre + stem + tsuf] = 0;
183- return out;
184- }
185- }
186-}
187-
188-static char *
189-substval(const char *val, const char *from, const char *to)
190-{
191- size_t i, j, n, cap, len, wn;
192- char *out, *part;
193-
194- n = strlen(val);
195- cap = n + 1;
196- len = 0;
197- out = xmalloc(cap);
198- for (i = 0; i < n;) {
199- if (isspace((unsigned char)val[i])) {
200- if (len + 2 > cap) {
201- cap *= 2;
202- out = xrealloc(out, cap);
203- }
204- out[len++] = val[i++];
205- continue;
206- }
207- j = i;
208- while (j < n && !isspace((unsigned char)val[j]))
209- j++;
210- part = substword(val + i, j - i, from, to);
211- wn = strlen(part);
212- if (len + wn + 1 > cap) {
213- cap = len + wn + 1;
214- out = xrealloc(out, cap);
215- }
216- memcpy(out + len, part, wn);
217- len += wn;
218- free(part);
219- i = j;
220- }
221- out[len] = 0;
222- return out;
223-}
224-
225-static int
226-issubstref(const char *s, size_t n, size_t *colon, size_t *eq)
227-{
228- size_t i;
229-
230- for (i = 0; i < n; i++) {
231- if (s[i] == ':') {
232- *colon = i;
233- break;
234- }
235- if (!(isalnum((unsigned char)s[i]) || s[i] == '_'))
236- return 0;
237- }
238- if (i == 0 || i >= n)
239- return 0;
240- for (i = *colon + 1; i < n; i++) {
241- if (s[i] == '=') {
242- *eq = i;
243- return i > *colon + 1;
244- }
245- }
246- return 0;
247-}
248-
249-static char *
250-expandstr(struct Env *env, const char *s)
251-{
252- size_t i, j, k, n, cap, len, inner, start, colon, eq;
253- char close;
254- char *out, *name, *val, *from, *to;
255- struct Var *v;
256-
257- n = strlen(s);
258- cap = n + 1;
259- len = 0;
260- out = xmalloc(cap);
261- for (i = 0; i < n; i++) {
262- if (s[i] != '$' || i + 1 >= n || (s[i + 1] != '(' && s[i + 1] != '{')) {
263- if (len + 2 > cap) {
264- cap *= 2;
265- out = xrealloc(out, cap);
266- }
267- out[len++] = s[i];
268- continue;
269- }
270- close = s[i + 1] == '(' ? ')' : '}';
271- start = i;
272- j = i + 2;
273- inner = 1;
274- while (j < n && inner) {
275- if (s[j] == '$' && j + 1 < n && (s[j + 1] == '(' || s[j + 1] == '{')) {
276- inner++;
277- j += 2;
278- continue;
279- }
280- if (s[j] == close)
281- inner--;
282- j++;
283- }
284- if (inner) {
285- if (len + (n - start) + 1 > cap) {
286- cap = len + (n - start) + 1;
287- out = xrealloc(out, cap);
288- }
289- memcpy(out + len, s + start, n - start);
290- len += n - start;
291- break;
292- }
293- if (isplainvar(s + i + 2, j - i - 3)) {
294- name = xstrndup(s + i + 2, j - i - 3);
295- v = findvar(env, name);
296- free(name);
297- val = v ? expandstr(env, v->val) : xstrdup("");
298- k = strlen(val);
299- if (len + k + 1 > cap) {
300- cap = len + k + 1;
301- out = xrealloc(out, cap);
302- }
303- memcpy(out + len, val, k);
304- len += k;
305- free(val);
306- } else if (issubstref(s + i + 2, j - i - 3, &colon, &eq)) {
307- name = xstrndup(s + i + 2, colon);
308- from = xstrndup(s + i + 2 + colon + 1, eq - colon - 1);
309- to = xstrndup(s + i + 2 + eq + 1, j - i - 4 - eq);
310- v = findvar(env, name);
311- free(name);
312- if (v) {
313- char *base;
314-
315- base = expandstr(env, v->val);
316- val = substval(base, from, to);
317- free(base);
318- } else {
319- val = xstrdup("");
320- }
321- free(from);
322- free(to);
323- k = strlen(val);
324- if (len + k + 1 > cap) {
325- cap = len + k + 1;
326- out = xrealloc(out, cap);
327- }
328- memcpy(out + len, val, k);
329- len += k;
330- free(val);
331- } else {
332- k = j - start;
333- if (len + k + 1 > cap) {
334- cap = len + k + 1;
335- out = xrealloc(out, cap);
336- }
337- memcpy(out + len, s + start, k);
338- len += k;
339- }
340- i = j - 1;
341- }
342- out[len] = 0;
343- return out;
344-}
345-
346-static void
347-setvar(struct Env *env, const char *name, char *val, int simple)
348-{
349- struct Var *v;
350-
351- v = findvar(env, name);
352- if (v) {
353- free(v->val);
354- v->val = val;
355- v->simple = simple;
356- return;
357- }
358- env->v = xrealloc(env->v, (env->n + 1) * sizeof(env->v[0]));
359- env->v[env->n].name = xstrdup(name);
360- env->v[env->n].val = val;
361- env->v[env->n].simple = simple;
362- env->n++;
363-}
364-
365-static void
366-seedenv(struct Env *env)
367-{
368- setvar(env, "CC", xstrdup("cc"), 1);
369- setvar(env, "CXX", xstrdup("c++"), 1);
370- setvar(env, "CPP", xstrdup("$(CC) -E"), 0);
371- setvar(env, "AR", xstrdup("ar"), 1);
372- setvar(env, "ARFLAGS", xstrdup("-rv"), 1);
373- setvar(env, "AS", xstrdup("as"), 1);
374- setvar(env, "LD", xstrdup("ld"), 1);
375- setvar(env, "LEX", xstrdup("lex"), 1);
376- setvar(env, "YACC", xstrdup("yacc"), 1);
377- setvar(env, "SHELL", xstrdup("/bin/sh"), 1);
378-}
379-
380-static void
381-freeenv(struct Env *env)
382-{
383- size_t i;
384-
385- for (i = 0; i < env->n; i++) {
386- free(env->v[i].name);
387- free(env->v[i].val);
388- }
389- free(env->v);
390- env->v = 0;
391- env->n = 0;
392-}
393-
394-static void
395-evalassign(struct Env *env, const struct AssignNode *in)
396-{
397- struct Var *v;
398- char *rhs, *joined;
399-
400- if (in->tspec)
401- return;
402- switch (in->op) {
403- case ASSIGN_EQ:
404- setvar(env, in->lhs, xstrdup(in->rhs), 0);
405- break;
406- case ASSIGN_COLON_EQ:
407- setvar(env, in->lhs, expandstr(env, in->rhs), 1);
408- break;
409- case ASSIGN_QMARK_EQ:
410- if (!findvar(env, in->lhs))
411- setvar(env, in->lhs, xstrdup(in->rhs), 0);
412- break;
413- case ASSIGN_PLUS_EQ:
414- v = findvar(env, in->lhs);
415- if (!v) {
416- setvar(env, in->lhs, xstrdup(in->rhs), 0);
417- break;
418- }
419- rhs = v->simple ? expandstr(env, in->rhs) : xstrdup(in->rhs);
420- joined = cat2(v->val, rhs);
421- free(rhs);
422- free(v->val);
423- v->val = joined;
424- break;
425- case ASSIGN_BANG_EQ:
426- setvar(env, in->lhs, expandstr(env, in->rhs), 1);
427- break;
428- }
429-}
430-
431-static int
432-testcond(struct Env *env, const struct CondNode *cond)
433-{
434- char *a, *b;
435- int ok;
436-
437- a = cond->arg1 ? expandstr(env, cond->arg1) : xstrdup("");
438- b = cond->arg2 ? expandstr(env, cond->arg2) : xstrdup("");
439- ok = strcmp(a, b) == 0;
440- free(a);
441- free(b);
442- if (cond->kind == COND_IFNEQ)
443- ok = !ok;
444- return ok;
445-}
446-
447-static void
448-copywords(struct StrList *out, const struct StrList *in, struct Env *env)
449-{
450- size_t i;
451-
452- memset(out, 0, sizeof(*out));
453- for (i = 0; i < in->n; i++) {
454- out->v = xrealloc(out->v, (out->n + 1) * sizeof(out->v[0]));
455- out->v[out->n++] = expandstr(env, in->v[i]);
456- }
457-}
458-
459-static void
460-copyrecipes(struct RecipeList *out, const struct RecipeList *in, struct Env *env)
461-{
462- size_t i;
463-
464- memset(out, 0, sizeof(*out));
465- for (i = 0; i < in->n; i++) {
466- out->v = xrealloc(out->v, (out->n + 1) * sizeof(out->v[0]));
467- out->v[out->n++] = expandstr(env, in->v[i]);
468- }
469-}
470-
471-static int
472-evalnodes(const struct NodeList *in, struct NodeList *out, struct Env *env)
473-{
474- size_t i;
475-
476- memset(out, 0, sizeof(*out));
477- for (i = 0; i < in->n; i++) {
478- const struct Node *src;
479- struct Node node;
480-
481- src = &in->v[i];
482- memset(&node, 0, sizeof(node));
483- node.kind = src->kind;
484- node.loc = src->loc;
485- switch (src->kind) {
486- case NODE_BLANK:
487- break;
488- case NODE_COMMENT:
489- case NODE_RAW:
490- node.data.raw.text = xstrdup(src->data.raw.text);
491- break;
492- case NODE_INCLUDE:
493- node.data.include.optional = src->data.include.optional;
494- node.data.include.path = expandstr(env, src->data.include.path);
495- break;
496- case NODE_COND:
497- if (testcond(env, &src->data.cond)) {
498- if (evalnodes(&src->data.cond.thenpart, out, env) < 0)
499- return -1;
500- } else {
501- if (evalnodes(&src->data.cond.elsepart, out, env) < 0)
502- return -1;
503- }
504- continue;
505- case NODE_ASSIGN:
506- node.data.assign.lhs = xstrdup(src->data.assign.lhs);
507- node.data.assign.op = src->data.assign.op;
508- node.data.assign.tspec = src->data.assign.tspec;
509- if (src->data.assign.op == ASSIGN_COLON_EQ || src->data.assign.op == ASSIGN_BANG_EQ)
510- node.data.assign.rhs = expandstr(env, src->data.assign.rhs);
511- else
512- node.data.assign.rhs = xstrdup(src->data.assign.rhs);
513- copywords(&node.data.assign.targets, &src->data.assign.targets, env);
514- evalassign(env, &src->data.assign);
515- break;
516- case NODE_RULE:
517- copywords(&node.data.rule.targets, &src->data.rule.targets, env);
518- copywords(&node.data.rule.prereqs, &src->data.rule.prereqs, env);
519- copywords(&node.data.rule.order_only, &src->data.rule.order_only, env);
520- copyrecipes(&node.data.rule.recipes, &src->data.rule.recipes, env);
521- break;
522- }
523- addnode(out, node);
524- }
525- return 0;
526-}
527-
528-int
529-eval(const struct Ast *ast, struct Ast *out)
530-{
531- struct Env env;
532- int rc;
533-
534- memset(&env, 0, sizeof(env));
535- seedenv(&env);
536- rc = evalnodes((const struct NodeList *)ast, (struct NodeList *)out, &env);
537- freeenv(&env);
538- return rc;
539-}
540-
541-static void
542-freestrs(struct StrList *list)
543-{
544- size_t i;
545-
546- for (i = 0; i < list->n; i++)
547- free(list->v[i]);
548- free(list->v);
549-}
550-
551-static void
552-freerec(struct RecipeList *list)
553-{
554- size_t i;
555-
556- for (i = 0; i < list->n; i++)
557- free(list->v[i]);
558- free(list->v);
559-}
560-
561-static void
562-freenodes(struct NodeList *list)
563-{
564- size_t i;
565-
566- for (i = 0; i < list->n; i++) {
567- switch (list->v[i].kind) {
568- case NODE_COMMENT:
569- case NODE_RAW:
570- free(list->v[i].data.raw.text);
571- break;
572- case NODE_ASSIGN:
573- free(list->v[i].data.assign.lhs);
574- free(list->v[i].data.assign.rhs);
575- freestrs(&list->v[i].data.assign.targets);
576- break;
577- case NODE_RULE:
578- freestrs(&list->v[i].data.rule.targets);
579- freestrs(&list->v[i].data.rule.prereqs);
580- freestrs(&list->v[i].data.rule.order_only);
581- freerec(&list->v[i].data.rule.recipes);
582- break;
583- case NODE_INCLUDE:
584- free(list->v[i].data.include.path);
585- break;
586- case NODE_COND:
587- free(list->v[i].data.cond.arg1);
588- free(list->v[i].data.cond.arg2);
589- free(list->v[i].data.cond.raw);
590- freenodes(&list->v[i].data.cond.thenpart);
591- freenodes(&list->v[i].data.cond.elsepart);
592- break;
593- case NODE_BLANK:
594- break;
595- }
596- }
597- free(list->v);
598- list->v = 0;
599- list->n = 0;
600-}
601-
602-void
603-freeast(struct Ast *ast)
604-{
605- freenodes((struct NodeList *)ast);
606-}
A
util.c
+57,
-0
1@@ -0,0 +1,57 @@
2+#include "internal.h"
3+
4+#include <stdio.h>
5+#include <stdlib.h>
6+#include <string.h>
7+
8+/* shared utility functions */
9+
10+void *
11+xmalloc(size_t n)
12+{
13+ void *p;
14+
15+ p = malloc(n ? n : 1);
16+ if (!p) {
17+ fprintf(stderr, "out of memory\n");
18+ exit(1);
19+ }
20+ return p;
21+}
22+
23+void *
24+xrealloc(void *p, size_t n)
25+{
26+ void *q;
27+
28+ q = realloc(p, n ? n : 1);
29+ if (!q) {
30+ fprintf(stderr, "out of memory\n");
31+ exit(1);
32+ }
33+ return q;
34+}
35+
36+char *
37+xstrndup(const char *s, size_t n)
38+{
39+ char *p;
40+
41+ p = xmalloc(n + 1);
42+ memcpy(p, s, n);
43+ p[n] = 0;
44+ return p;
45+}
46+
47+char *
48+xstrdup(const char *s)
49+{
50+ return xstrndup(s, strlen(s));
51+}
52+
53+void
54+addnode(struct NodeList *list, struct Node node)
55+{
56+ list->v = xrealloc(list->v, (list->n + 1) * sizeof(list->v[0]));
57+ list->v[list->n++] = node;
58+}