aboutsummaryrefslogtreecommitdiff
path: root/attr.c
diff options
context:
space:
mode:
authorMichael Forney <mforney@mforney.org>2021-10-24 22:47:44 -0700
committerMichael Forney <mforney@mforney.org>2024-03-24 02:41:18 -0700
commit731e7a2f3bf18baa4d4ce966006637ee13c5651a (patch)
tree8bc4457c7c663b544ccc0386dbabcccd7259a45a /attr.c
parent7585cbb758b7bc2169cba42b7665d46f0c57db93 (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.c90
1 files changed, 90 insertions, 0 deletions
diff --git a/attr.c b/attr.c
new file mode 100644
index 0000000..75ec5ef
--- /dev/null
+++ b/attr.c
@@ -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;
+}