commit - 89fd2bea5a51ccb48581f8c7acf5788e35ead60a
commit + 69bdd906cbdaaab353fb7f2d20fd70c31c19d31d
blob - 7fd8be6ca2455868777513733d2496ac021f1e17
blob + 197094d148d98d5113efad3d6bd01f9a877d85fc
--- configure.ac
+++ configure.ac
AM_INIT_AUTOMAKE([-Wall foreign subdir-objects])
AC_PROG_CC_C99
AC_USE_SYSTEM_EXTENSIONS
+AC_PROG_YACC
PKG_PROG_PKG_CONFIG
blob - /dev/null
blob + e03c44868486748ab561d70e313109cd0f80d495 (mode 644)
--- /dev/null
+++ parse.y
+/*
+ * Much of the design is taken from doas (parse.y rev 1.29)
+ *
+ * Copyright (c) 2021 Omar Polo <op@omarpolo.com>
+ * Copyright (c) 2015 Ted Unangst <tedu@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+%{
+
+#include "telescope.h"
+
+#include <ctype.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct {
+ union {
+ char *str;
+ int num;
+ };
+ int lineno;
+ int colno;
+} yystype;
+#define YYSTYPE yystype
+
+static const char *path;
+
+FILE *yyfp;
+
+int parse_errors = 0;
+
+static void yyerror(const char *, ...);
+static int yylex(void);
+
+%}
+
+%token TSET
+%token TSTYLE TPRFX TCONT TBG TFG TATTR TBOLD TUNDERLINE
+%token TBIND TUNBIND
+
+%token <str> TSTRING
+%token <num> TNUMBER
+
+%%
+
+grammar : /* empty */
+ | grammar '\n'
+ | grammar rule '\n'
+ | error '\n'
+ ;
+
+rule : set | style | bind | unbind ;
+
+set : TSET TSTRING '=' TSTRING { printf("set %s = \"%s\"\n", $2, $4); }
+ | TSET TSTRING '=' TNUMBER { printf("set %s = %d\n", $2, $4); }
+ ;
+
+style : TSTYLE TSTRING { printf("(%s) ", $2); } styleopt
+ | TSTYLE TSTRING { printf("[%s]\n", $2); } '{' styleopts '}'
+ ;
+
+styleopts : /* empty */
+ | styleopts '\n'
+ | styleopts styleopt '\n'
+ ;
+
+styleopt : TPRFX TSTRING { printf("style prefix setted to \"%s\"\n", $2); }
+ | TCONT TSTRING { printf("style cont setted to \"%s\"\n", $2); }
+ | TBG TSTRING { printf("style background setted to \"%s\"\n", $2); }
+ | TFG TSTRING { printf("style foreground setted to \"%s\"\n", $2); }
+ | TATTR TBOLD { printf("style attr setted to bold\n"); }
+ | TATTR TUNDERLINE { printf("style attr setted to underline\n"); }
+ ;
+
+bind : TBIND TSTRING TSTRING TSTRING { printf("TODO: bind %s %s %s\n", $2, $3, $4); }
+ ;
+
+unbind : TUNBIND TSTRING TSTRING { printf("TODO: unbind %s %s\n", $2, $3); }
+ ;
+
+%%
+
+void
+yyerror(const char *fmt, ...)
+{
+ va_list va;
+
+ fprintf(stderr, "%s:%d ", path, yylval.lineno+1);
+ va_start(va, fmt);
+ vfprintf(stderr, fmt, va);
+ va_end(va);
+ fprintf(stderr, "\n");
+ parse_errors++;
+}
+
+static struct keyword {
+ const char *word;
+ int token;
+} keywords[] = {
+ { "set", TSET },
+ { "style", TSTYLE },
+ { "prefix", TPRFX },
+ { "cont", TCONT },
+ { "background", TBG },
+ { "foreground", TFG },
+ { "attr", TATTR },
+ { "bold", TBOLD },
+ { "underline", TUNDERLINE },
+ { "bind", TBIND },
+ { "unbind", TUNBIND },
+};
+
+int
+yylex(void)
+{
+ char buf[1024], *ebuf, *p, *str;
+ const char *errstr;
+ int c, quotes = 0, escape = 0, qpos = -1, nonkw = 0;
+ size_t i;
+
+ p = buf;
+ ebuf = buf + sizeof(buf);
+
+repeat:
+ /* skip whitespace first */
+ for (c = getc(yyfp); c == ' ' || c == '\t' || c == '\f'; c = getc(yyfp))
+ yylval.colno++;
+
+ /* check for special one-character constructions */
+ switch (c) {
+ case '\n':
+ yylval.colno = 0;
+ yylval.lineno++;
+ /* fallthrough */
+ case '{':
+ case '}':
+ case '=':
+ return c;
+ case '#':
+ /* skip comments; NUL is allowed; no continuation */
+ while ((c = getc(yyfp)) != '\n')
+ if (c == EOF)
+ goto eof;
+ yylval.colno = 0;
+ yylval.lineno++;
+ return c;
+ case EOF:
+ goto eof;
+ }
+
+ /* parsing next word */
+ for (;; c = getc(yyfp), yylval.colno++) {
+ switch (c) {
+ case '\0':
+ yyerror("unallowed character NULL in column %d",
+ yylval.colno+1);
+ escape = 0;
+ continue;
+ case '\\':
+ escape = !escape;
+ if (escape)
+ continue;
+ break;
+ case '\n':
+ if (quotes)
+ yyerror("unterminated quotes in column %d",
+ yylval.colno+1);
+ if (escape) {
+ nonkw = 1;
+ escape = 0;
+ yylval.colno = 0;
+ yylval.lineno++;
+ }
+ goto eow;
+ case EOF:
+ if (escape)
+ yyerror("unterminated escape in column %d",
+ yylval.colno);
+ if (quotes)
+ yyerror("unterminated quotes in column %d",
+ qpos + 1);
+ goto eow;
+ case '{':
+ case '}':
+ case '=':
+ case '#':
+ case ' ':
+ case '\t':
+ if (!escape && !quotes)
+ goto eow;
+ break;
+ case '"':
+ if (!escape) {
+ quotes = !quotes;
+ if (quotes) {
+ nonkw = 1;
+ qpos = yylval.colno;
+ }
+ continue;
+ }
+ }
+ *p++ = c;
+ if (p == ebuf) {
+ yyerror("line too long");
+ p = buf;
+ }
+ escape = 0;
+ }
+
+eow:
+ *p = 0;
+ if (c != EOF)
+ ungetc(c, yyfp);
+ if (p == buf) {
+ /*
+ * There could be a number of reason for empty buffer,
+ * and we handle all of them here, to avoid cluttering
+ * the main loop.
+ */
+ if (c == EOF)
+ goto eof;
+ else if (qpos == -1) /* accept, e.g., empty args: cmd foo args "" */
+ goto repeat;
+ }
+ if (!nonkw) {
+ for (i = 0; i < sizeof(keywords) / sizeof(keywords[0]); i++) {
+ if (strcmp(buf, keywords[i].word) == 0)
+ return keywords[i].token;
+ }
+ }
+ c = *buf;
+ if (!nonkw && (c == '-' || isdigit(c))) {
+ yylval.num = strtonum(buf, INT_MIN, INT_MAX, &errstr);
+ if (errstr != NULL)
+ yyerror("number is %s: %s", errstr, buf);
+ return TNUMBER;
+ }
+ if ((str = strdup(buf)) == NULL)
+ err(1, "%s", __func__);
+ yylval.str = str;
+ return TSTRING;
+
+eof:
+ if (ferror(yyfp))
+ yyerror("input error reading config");
+ return 0;
+}
+
+void
+parseconfig(const char *filename, int fonf)
+{
+ if ((yyfp = fopen(filename, "r")) == NULL) {
+ if (fonf)
+ err(1, "%s", filename);
+ return;
+ }
+
+ path = filename;
+ yyparse();
+ fclose(yyfp);
+ if (parse_errors)
+ exit(1);
+}