aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cc.h2
-rw-r--r--pp.c9
-rw-r--r--token.c30
3 files changed, 36 insertions, 5 deletions
diff --git a/cc.h b/cc.h
index 25a5fc0..bb5e23b 100644
--- a/cc.h
+++ b/cc.h
@@ -376,8 +376,8 @@ struct init {
extern struct token tok;
void tokprint(const struct token *);
+void tokdesc(char *, size_t, enum tokenkind, const char *);
_Noreturn void error(const struct location *, const char *, ...);
-struct token;
/* scan */
diff --git a/pp.c b/pp.c
index 757492b..f334f07 100644
--- a/pp.c
+++ b/pp.c
@@ -124,10 +124,13 @@ peek(int kind)
char *
expect(int kind, const char *msg)
{
- char *lit;
+ char *lit, want[64], got[64];
- if (tok.kind != kind)
- error(&tok.loc, "expected %d %s, saw %d", kind, msg, tok.kind);
+ if (tok.kind != kind) {
+ tokdesc(want, sizeof(want), kind, NULL);
+ tokdesc(got, sizeof(got), tok.kind, tok.lit);
+ error(&tok.loc, "expected %s %s, saw %s", want, msg, got);
+ }
lit = tok.lit;
next();
diff --git a/token.c b/token.c
index fe358a9..3a97f7a 100644
--- a/token.c
+++ b/token.c
@@ -1,4 +1,6 @@
+#include <assert.h>
#include <stdarg.h>
+#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -7,7 +9,7 @@
struct token tok;
-static char *tokstr[] = {
+static const char *tokstr[] = {
/* keyword */
[TAUTO] = "auto",
[TBREAK] = "break",
@@ -130,6 +132,32 @@ tokprint(const struct token *t)
fputs(str, stdout);
}
+void
+tokdesc(char *buf, size_t len, enum tokenkind kind, const char *lit)
+{
+ const char *class;
+ bool quote;
+
+ switch (kind) {
+ case TIDENT: class = "identifier"; quote = true; break;
+ case TNUMBER: class = "number"; quote = true; break;
+ case TCHARCONST: class = "character"; quote = false; break;
+ case TSTRINGLIT: class = "string"; quote = false; break;
+ case TNEWLINE: class = "newline"; quote = true; break;
+ default:
+ class = NULL;
+ lit = kind < LEN(tokstr) ? tokstr[kind] : NULL;
+ }
+ if (class && lit)
+ snprintf(buf, len, quote ? "%s '%s'" : "%s %s", class, lit);
+ else if (class)
+ snprintf(buf, len, "%s", class);
+ else if (lit)
+ snprintf(buf, len, "'%s'", lit);
+ else
+ snprintf(buf, len, "<unknown>");
+}
+
_Noreturn void error(const struct location *loc, const char *fmt, ...)
{
va_list ap;