aboutsummaryrefslogtreecommitdiff
path: root/sys/cmd/cc/pp.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/cmd/cc/pp.c')
-rw-r--r--sys/cmd/cc/pp.c92
1 files changed, 82 insertions, 10 deletions
diff --git a/sys/cmd/cc/pp.c b/sys/cmd/cc/pp.c
index 8de4792..16fac29 100644
--- a/sys/cmd/cc/pp.c
+++ b/sys/cmd/cc/pp.c
@@ -110,8 +110,10 @@ opand(Lexer *lx)
switch (tok.kind & ~Vmask) {
case Vint: case Vlong: case Vvlong:
return tok.val.i;
- case Vint | Vun: case Vlong | Vun: case Vvlong | Vun:
+ case Vun|Vint : case Vun|Vlong : case Vun|Vvlong:
return tok.val.ui;
+ case Vrune:
+ return tok.val.r;
case Vchar:
return tok.val.c;
default:
@@ -383,7 +385,7 @@ enum
{
PPbeg = 0x02,
PParg = 0x03,
- PPtok = 0x04,
+ PPcat = 0x04,
PPstr = 0x05,
PPvar = 0x80,
@@ -435,9 +437,9 @@ static
error
ppdef(Lexer *lx)
{
- byte b;
+ int b;
Sym *sym;
- int i, n, dot;
+ int i, j, f, n, dot;
string s, a, buf, args[PPnarg];
s = ident(lx);
@@ -503,12 +505,47 @@ ppdef(Lexer *lx)
for (i = 0; i < n; i++) {
if (strcmp(lx->buf, args[i]) == 0) {
- goto Arg;
+ goto Args;
}
}
str·appendlen(&buf, (lx->b - lx->buf), lx->buf);
continue;
+ Args:
+ /* Check for argx ## argy OR argx##argy */
+ if (isspace(b)) {
+ b = getnsbyte(lx);
+ f = 1;
+ }
+ if (b == '#') {
+ b = getbyte(lx);
+ if (b != '#') {
+ ungetbyte(lx);
+ goto Arg;
+ }
+ b = getnsbyte(lx);
+ lx->b = lx->buf;
+ while (isalnum(b) || b == '_') {
+ *lx->b++ = b;
+ b = getbyte(lx);
+ }
+ *lx->b = '\0';
+
+ for (j = 0; j < n; j++) {
+ if (strcmp(lx->buf, args[j]) == 0)
+ goto CatArgs;
+ }
+ errorat(lx->pos, "macro operator '##' must be terminated by valid variable identifier");
+ goto Bad;
+ CatArgs:
+ str·appendbyte(&buf, PPcat);
+ str·appendbyte(&buf, 'a' + i);
+ str·appendbyte(&buf, 'a' + j);
+ continue;
+ }
Arg:
+ if (f)
+ ungetbyte(lx);
+
str·appendbyte(&buf, PParg);
str·appendbyte(&buf, 'a' + i);
continue;
@@ -564,8 +601,29 @@ ppdef(Lexer *lx)
break;
}
- if (b == '#' && n > 0) {
- panicf("tokenizer needs implementation");
+ if (b == '#') {
+ b = getnsbyte(lx);
+ if (b == '#') {
+ errorat(lx->pos, "macro operator '##' must be proceeded by a valid variable identifier");
+ goto Bad;
+ }
+ lx->b = lx->buf;
+ while (isalnum(b) || b == '_') {
+ *lx->b++ = b;
+ b = getbyte(lx);
+ }
+ *lx->b = '\0';
+
+ for (i = 0; i < n; i++) {
+ if (strcmp(lx->buf, args[i]) == 0)
+ goto Str;
+ }
+ errorat(lx->pos, "macro operator '#' must be followed by a valid variable identifier");
+ goto Bad;
+ Str:
+ str·appendbyte(&buf, PPstr);
+ str·appendbyte(&buf, 'a' + i);
+ continue;
}
str·appendbyte(&buf, b);
@@ -578,10 +636,12 @@ ppdef(Lexer *lx)
if (dot)
*buf |= PPvar;
- sym = defmacro(lx, s, buf);
+ lx->b = lx->buf;
+ sym = defmacro(lx, s, buf);
return 0;
Bad:
errorat(lx->pos, "failed parse of #define macro '%s'", s);
+ lx->b = lx->buf;
ppend(lx);
return 1;
}
@@ -733,9 +793,21 @@ expandmacro(Lexer *lx, Sym *s, byte *dst)
dst += strlen(arg[b]);
break;
- case PPtok:
case PPstr:
- panicf("haven't implemented");
+ b = *it++;
+ b -= 'a';
+ *dst++ = '"';
+ strcpy(dst, arg[b]);
+ *dst++ = '"';
+ break;
+
+ case PPcat:
+ b = *it++;
+ b -= 'a';
+ strcpy(dst, arg[b]);
+ b = *it++;
+ b -= 'a';
+ strcpy(dst, arg[b]);
break;
case '\0':