Added package with the documentation and the examples
[lwc.git] / templates.c
blob1baef39a7323604b8aba13490056c9175d79ee8a
1 #include "global.h"
3 #define TEMPLATE_COMMA "templ_comma"
4 #define TEMPLATE_PARENTH "templ_parenth"
6 typedef struct {
7 Token *BODY;
8 int len, argc;
9 } Template;
11 static Token *OCD;
12 static int nocd, ncdpt;
14 static inline void output_templtok (Token i)
16 if (nocd == ncdpt)
17 OCD = (Token*) realloc (OCD, sizeof (Token) * (nocd += 512));
18 OCD [ncdpt++] = i;
21 static Template **tpls;
23 #define CONCAT_CMD 1
24 #define FINISH_CMD 2
26 static void _export_token (Token t)
28 static Token lasttok;
29 static bool concatenation = false;
31 if (t == FINISH_CMD) {
32 if (lasttok) output_itoken (GLOBAL, lasttok);
33 } else if (t == CONCAT_CMD) {
34 if (concatenation) return;
35 if (!lasttok) return;
36 concatenation = true;
37 } else if (!ISSYMBOL (t) && !ISRESERVED (t) && !ISVALUE (t)) {
38 if (lasttok) output_itoken (GLOBAL, lasttok);
39 output_itoken (GLOBAL, t);
40 lasttok = 0;
41 concatenation = false;
42 } else if (!concatenation) {
43 if (lasttok) output_itoken (GLOBAL, lasttok);
44 lasttok = t;
45 } else {
46 char *tmp = (char*) alloca (strlen (expand (lasttok)) + strlen (expand (t)) + 1);
47 strcat (strcpy (tmp, expand (lasttok)), expand (t));
48 lasttok = new_symbol (strdup (tmp));
52 static void export_token (Token t)
54 static int havelev;
55 if (t == '>' && !havelev) {
56 havelev = 1;
57 return;
59 if (t == '<' && havelev) {
60 _export_token (CONCAT_CMD);
61 havelev = 0;
62 return;
64 if (havelev) {
65 _export_token ('>');
66 havelev = 0;
68 _export_token (t);
71 static void expand_template (Template *t, Token **argv)
73 NormPtr i, len = t->len;
74 Token *BODY = t->BODY;
76 for (i = 0; i < len; i++)
77 if (ISTPLARG (BODY [i])) {
78 Token *p = argv [BODY [i] - ARGBASE];
79 while (*p != -1)
80 export_token (*p++);
81 } else export_token (BODY [i]);
82 export_token (FINISH_CMD);
85 static NormPtr expand_parse_template (NormPtr i)
87 Template *t = tpls [CODE [i++] - IDENTBASE];
88 Token **argv = (Token**) alloca (t->argc * sizeof (Token*)), *argvv;
89 int argc, c;
90 NormPtr s;
92 if (CODE [i++] != '(') parse_error (i, "template invokation");
93 for (argc = 0; argc < t->argc; i++) {
94 s = i;
95 while (CODE [i] != ',' && CODE [i] != ')')
96 i++;
97 argv [argc++] = argvv = (Token*) alloca ((1 + i - s) * sizeof (Token));
98 intextract (argvv, &CODE [s], i - s);
99 for (c = 0; argvv [c] != -1; c++)
100 if (!tokcmp (argvv [c], TEMPLATE_COMMA))
101 argvv [c] = ',';
102 else if (!tokcmp (argvv [c], TEMPLATE_PARENTH))
103 argvv [c] = ')';
104 if (CODE [i] == ')') break;
106 if (argc < t->argc) parse_error (i, "too few arguments to template");
107 if (CODE [i] != ')') parse_error (i, "too many arguments to template");
108 expand_template (t, argv);
110 return i;
113 static NormPtr templatedef (NormPtr i)
115 NormPtr pstart = i;
116 Token tname = CODE [i++];
117 Token targ [32];
118 int argc = 0, j, blockno;
120 if (!ISSYMBOL (tname)) parse_error (i, "template name missing");
121 if (tpls [tname - IDENTBASE]) parse_error (i, "template redefined");
122 if (CODE [i++] != '(') parse_error (i, "template name '('");
123 for (;;i++) {
124 targ [argc] = CODE [i++];
125 if (!ISSYMBOL (targ [argc])) parse_error (i, "template argument name");
126 argc++;
127 if (CODE [i] == ',') continue;
128 break;
130 if (CODE [i++] != ')' || argc == 0)
131 parse_error (i, "bad argument list for template");
133 OCD = (Token*) malloc ((nocd = 512) * sizeof (Token));
134 ncdpt = 0;
136 if (CODE [i++] != '{') parse_error (i, "template '{'");
138 for (blockno = 1; CODE [i] != -1; i++)
139 if (ISSYMBOL (CODE [i])) {
140 for (j = 0; j < argc; j++)
141 if (CODE [i] == targ [j]) break;
142 if (j < argc) {
143 output_templtok (ARGBASE + j);
144 continue;
146 output_templtok (CODE [i]);
147 } else if (CODE [i] == '{') {
148 output_templtok ('{');
149 ++blockno;
150 } else if (CODE [i] == '}') {
151 if (--blockno == 0) break;
152 output_templtok ('}');
153 } else output_templtok (CODE [i]);
155 if (CODE [i] == -1) parse_error (i, "unclosed template definition");
157 Template *t = tpls [tname - IDENTBASE] = (Template*) malloc (sizeof (Template));
158 t->BODY = (Token*) realloc (OCD, ncdpt * sizeof (Token));
159 t->len = ncdpt;
160 t->argc = argc;
162 adjust_lines (pstart, pstart - i);
164 return i;
167 static void pass ()
169 NormPtr i;
171 for (i = 0; CODE [i] != -1; i++)
172 if (CODE [i] == RESERVED_template
173 && CODE [i + 1] != RESERVED_class && CODE [i + 1] != RESERVED_struct)
174 i = templatedef (i + 1);
175 else if (ISSYMBOL (CODE [i]) && tpls [CODE [i] - IDENTBASE])
176 i = expand_parse_template (i);
177 else output_itoken (GLOBAL, CODE [i]);
179 output_itoken (GLOBAL, -1);
182 void do_templates ()
184 int i;
186 GLOBAL = new_stream ();
187 tpls = (Template**) alloca (c_nsym * sizeof (Template*));
189 for (i = 0; i < c_nsym; i++)
190 tpls [i] = 0;
192 pass ();
194 for (i = 0; i < c_nsym; i++)
195 if (tpls [i]) {
196 free (tpls [i]->BODY);
197 free (tpls [i]);
199 free (CODE);
200 CODE = combine_output (GLOBAL);