diff options
author | Michael Forney <mforney@mforney.org> | 2021-10-24 22:47:44 -0700 |
---|---|---|
committer | Michael Forney <mforney@mforney.org> | 2024-03-24 02:41:18 -0700 |
commit | 731e7a2f3bf18baa4d4ce966006637ee13c5651a (patch) | |
tree | 8bc4457c7c663b544ccc0386dbabcccd7259a45a /attr.c | |
parent | 7585cbb758b7bc2169cba42b7665d46f0c57db93 (diff) |
Add support for C23 attribute syntax
Currently, all attributes are ignored.
References: https://todo.sr.ht/~mcf/cproc/68
Diffstat (limited to 'attr.c')
-rw-r--r-- | attr.c | 90 |
1 files changed, 90 insertions, 0 deletions
@@ -0,0 +1,90 @@ +#include <stdbool.h> +#include <stdint.h> +#include <string.h> +#include "util.h" +#include "cc.h" + +enum attrprefix { + PREFIXNONE = 1, /* standard attribute */ + PREFIXGNU, +}; + +static char * +strip(char *name) +{ + size_t len; + + len = strlen(name); + if (len >= 4 && name[0] == '_' && name[1] == '_' && name[len - 2] == '_' && name[len - 1] == '_') { + name[len - 2] = '\0'; + name += 2; + } + return name; +} + +static bool +parseattr(struct attr *a, enum attrkind allowed, enum attrprefix prefix) +{ + char *name, *prefixname = ""; + enum attrkind kind; + int paren; + + if (tok.kind != TIDENT) + return false; + name = strip(tok.lit); + next(); + if (!prefix) { + if (consume(TCOLONCOLON)) { + if (strcmp(name, "gnu") == 0) + prefix = PREFIXGNU; + else + prefix = 0; + name = strip(expect(TIDENT, "after attribute prefix")); + } else { + prefix = PREFIXNONE; + } + } + kind = 0; + switch (prefix) { + case PREFIXGNU: + prefixname = "GNU "; + break; + } + if (kind) { + if (!(kind & allowed)) + error(&tok.loc, "%sattribute '%s' is not supported here", prefixname, name); + if (a) + a->kind |= kind; + } else if (consume(TLPAREN)) { + /* skip arguments */ + for (paren = 1; paren > 0; next()) { + switch (tok.kind) { + case TLPAREN: ++paren; break; + case TRPAREN: --paren; break; + } + } + } + return true; +} + +static bool +attrspec(struct attr *a, enum attrkind allowed) +{ + if (tok.kind != TLBRACK || !peek(TLBRACK)) + return false; + while (parseattr(a, allowed, 0) || consume(TCOMMA)) + ; + expect(TRBRACK, "to end attribute specifier"); + expect(TRBRACK, "to end attribute specifier"); + return true; +} + +bool +attr(struct attr *a, enum attrkind allowed) +{ + if (!attrspec(a, allowed)) + return false; + while (attrspec(a, allowed)) + ; + return true; +} |