diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/.gitignore | 4 | ||||
-rw-r--r-- | lib/Makefile.am | 15 | ||||
-rw-r--r-- | lib/diag.c | 181 | ||||
-rw-r--r-- | lib/forlan.c | 258 | ||||
-rw-r--r-- | lib/forlan.h | 123 | ||||
-rw-r--r-- | lib/forlangrm.y | 237 | ||||
-rw-r--r-- | lib/forlanlex.l | 137 | ||||
-rw-r--r-- | lib/libeclat.h | 33 |
8 files changed, 988 insertions, 0 deletions
diff --git a/lib/.gitignore b/lib/.gitignore new file mode 100644 index 0000000..e0d9b22 --- /dev/null +++ b/lib/.gitignore @@ -0,0 +1,4 @@ +forlangrm.c +forlangrm.h +forlangrm.output +forlanlex.c diff --git a/lib/Makefile.am b/lib/Makefile.am index 2c1d3a8..50b28a5 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -18,6 +18,12 @@ noinst_LIBRARIES=libeclat.a libeclat_a_SOURCES=\ base64.c\ + diag.c\ + forlan.c\ + forlan.h\ + forlangrm.h\ + forlangrm.y\ + forlanlex.l\ hmac_sha1.c\ libeclat.h\ q2url.c\ @@ -33,3 +39,12 @@ libeclat_a_SOURCES=\ AM_LDFLAGS = $(CURL_LIBS) INCLUDES = -I$(top_srcdir)/grecs/src/ $(CURL_CFLAGS) + +forlanlex.c: forlangrm.h +forlangrm.c forlangrm.h: forlangrm.y + +AM_YFLAGS=-tdv +AM_LFLAGS=-dvp + + + diff --git a/lib/diag.c b/lib/diag.c new file mode 100644 index 0000000..d061e9e --- /dev/null +++ b/lib/diag.c @@ -0,0 +1,181 @@ +/* This file is part of Eclat. + Copyright (C) 2012 Sergey Poznyakoff. + + Eclat is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + Eclat is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Eclat. If not, see <http://www.gnu.org/licenses/>. */ + +#include "libeclat.h" +#include <string.h> +#include <sysexits.h> + +const char *program_name; +struct debug_category debug_category[LIBECLAT_DBG_MAX]; +int debug_avail; + +void +set_program_name(const char *arg) +{ + program_name = strrchr(arg, '/'); + if (!program_name) + program_name = arg; + else + program_name++; +} + +void +vdiag(grecs_locus_t const *locus, const char *qual, const char *fmt, + va_list ap) +{ + if (program_name) + fprintf(stderr, "%s: ", program_name); + + if (locus) { + size_t size = 0; + + if (locus->beg.col == 0) + fprintf(stderr, "%s:%u", + locus->beg.file, + locus->beg.line); + else if (strcmp(locus->beg.file, locus->end.file)) + fprintf(stderr, "%s:%u.%u-%s:%u.%u", + locus->beg.file, + locus->beg.line, locus->beg.col, + locus->end.file, + locus->end.line, locus->end.col); + else if (locus->beg.line != locus->end.line) + fprintf(stderr, "%s:%u.%u-%u.%u", + locus->beg.file, + locus->beg.line, locus->beg.col, + locus->end.line, locus->end.col); + else + fprintf(stderr, "%s:%u.%u-%u", + locus->beg.file, + locus->beg.line, locus->beg.col, + locus->end.col); + fprintf(stderr, ": "); + } + + if (qual) + fprintf(stderr, "%s: ", qual); + vfprintf(stderr, fmt, ap); + fputc('\n', stderr); +} + +void +diag(grecs_locus_t const *locus, const char *qual, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vdiag(locus, qual, fmt, ap); + va_end(ap); +} + +void +die(int status, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vdiag(NULL, NULL, fmt, ap); + va_end(ap); + exit(status); +} + +void +err(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vdiag(NULL, NULL, fmt, ap); + va_end(ap); +} + +void +warn(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vdiag(NULL, "warning", fmt, ap); + va_end(ap); +} + +void +debug_printf(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vdiag(NULL, "debug", fmt, ap); + va_end(ap); +} + +static struct debug_category * +find_category(const char *arg, size_t len) +{ + struct debug_category *dp; + + for (dp = debug_category; dp < debug_category + debug_avail; dp++) + if (dp->length == len && memcmp(dp->name, arg, len) == 0) + return dp; + return NULL; +} + +int +parse_debug_level(const char *arg) +{ + unsigned long lev; + char *p; + size_t len = strcspn(arg, "."); + struct debug_category *dp; + + if (arg[len] == 0) { + lev = strtoul(arg, &p, 10); + if (*p) + return -1; + for (dp = debug_category; dp < debug_category + debug_avail; + dp++) + dp->level = lev; + return 0; + } + + dp = find_category(arg, len); + if (!dp) + return -1; + + p = (char*) arg + len; + if (*p == 0) + lev = 100; + else if (*p != '.') + return -1; + else { + lev = strtoul(p + 1, &p, 10); + if (*p) + return -1; + } + dp->level = lev; + return 0; +} + +int +debug_register(char *name) +{ + if (debug_avail >= LIBECLAT_DBG_MAX) + die(EX_SOFTWARE, "no more debug slots available"); + debug_category[debug_avail].name = grecs_strdup(name); + debug_category[debug_avail].length = strlen(name); + debug_category[debug_avail].level = 0; + return debug_avail++; +} diff --git a/lib/forlan.c b/lib/forlan.c new file mode 100644 index 0000000..0854d08 --- /dev/null +++ b/lib/forlan.c @@ -0,0 +1,258 @@ +/* This file is part of Eclat. + Copyright (C) 2012 Sergey Poznyakoff. + + Eclat is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + Eclat is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Eclat. If not, see <http://www.gnu.org/licenses/>. */ + +#include "libeclat.h" +#include "grecs.h" +#include "forlan.h" + +int forlan_dbg = -1; + +void +forlan_init() +{ + forlan_dbg = debug_register("forlan"); +} + +union forlan_node * +forlan_node_create(enum forlan_type type) +{ + union forlan_node *p = grecs_zalloc(sizeof(*p)); + p->type = type; + return p; +} + +static void f_dump_node(FILE *fp, union forlan_node *p, int *num, int lev); + + +static void +free_type_null(union forlan_node *p) +{ + warn("freeing undefined forlan_node"); +} + +void +dump_null(FILE *fp, union forlan_node *p, int *num, int lev) +{ + fprintf(fp, "[undefined node]\n"); +} + +static void +free_type_comp(union forlan_node *p) +{ + forlan_node_free(p->comp.node); +} +void +dump_comp(FILE *fp, union forlan_node *p, int *num, int lev) +{ + fprintf(fp, "COMP"); + if (p->comp.abs) + fprintf(fp, " ABS"); + fputc('\n', fp); + forlan_dump_node(fp, p->comp.node, num, lev + 1); +} + +static void +free_type_test(union forlan_node *p) +{ + free(p->test.comp); + free(p->test.value); +} +void +dump_test(FILE *fp, union forlan_node *p, int *num, int lev) +{ + fprintf(fp, "TEST: %s[%s]\n", p->test.comp, p->test.value); +} + +static void +free_type_func(union forlan_node *p) +{ + grecs_list_free(p->func.args); +} +void +dump_func(FILE *fp, union forlan_node *p, int *num, int lev) +{ + struct grecs_list_entry *ep; + fprintf(fp, "CALL: %s\n", p->func.fp); + if (p->func.args) + for (ep = p->func.args->head; ep; ep = ep->next) + forlan_dump_node(fp, ep->data, num, lev + 1); +} + +static void +free_type_cond(union forlan_node *p) +{ + forlan_node_free((union forlan_node *)p->cond.expr); + forlan_node_free(p->cond.iftrue); + forlan_node_free(p->cond.iffalse); +} +void +dump_cond(FILE *fp, union forlan_node *p, int *num, int lev) +{ + int n = *num; + fprintf(fp, "COND\n"); + forlan_dump_node(fp, p->cond.expr, num, lev + 1); + fprintf(fp, "%04d: %*.*sIFTRUE %04d\n", ++*num, lev, lev, "", n); + forlan_dump_node(fp, p->cond.iftrue, num, lev + 1); + fprintf(fp, "%04d: %*.*sIFFALSE %04d\n", ++*num, lev, lev, "", n); + forlan_dump_node(fp, p->cond.iffalse, num, lev + 1); +} + +static void +free_type_stmt(union forlan_node *p) +{ + forlan_node_free(p->stmt.stmt); + forlan_node_free(p->stmt.next); +} +void +dump_stmt(FILE *fp, union forlan_node *p, int *num, int lev) +{ + f_dump_node(fp, p->stmt.stmt, num, lev); + forlan_dump_node(fp, p->stmt.next, num, lev); +} + +static void +free_type_lit(union forlan_node *p) +{ + free(p->lit.string); +} +void +dump_lit(FILE *fp, union forlan_node *p, int *num, int lev) +{ + fprintf(fp, "LIT: \"%s\"\n", p->lit.string); +} + +static void +free_type_expr(union forlan_node *p) +{ + forlan_node_free(p->expr.arg[0]); + forlan_node_free(p->expr.arg[1]); +} +void +dump_expr(FILE *fp, union forlan_node *p, int *num, int lev) +{ + static char *opstr[] = { "NODE", "AND", "OR", "NOT" }; + + fprintf(fp, "%s\n", opstr[p->expr.opcode]); + forlan_dump_node(fp, p->expr.arg[0], num, lev + 1); + if (p->expr.arg[1]) + forlan_dump_node(fp, p->expr.arg[1], num, lev + 1); +} + +static void +free_type_last(union forlan_node *p) +{ +} +void +dump_last(FILE *fp, union forlan_node *p, int *num, int lev) +{ + fprintf(fp, "LAST\n"); +} + +struct forlan_node_method { + void (*f_free)(union forlan_node *); + void (*f_dump)(FILE *fp, union forlan_node *node, int *num, int lev); +}; + +static struct forlan_node_method f_tab[] = { + free_type_null, dump_null, /* Unknown/unset type */ + free_type_comp, dump_comp, /* A path component */ + free_type_test, dump_test, /* Value test (f[X]) */ + free_type_func, dump_func, /* Function call */ + free_type_cond, dump_cond, /* Conditional */ + free_type_stmt, dump_stmt, /* Statement */ + free_type_lit, dump_lit, /* Literal */ + free_type_expr, dump_expr, /* Boolean expression */ + free_type_last, dump_last, /* "last" */ +}; + +void +forlan_node_free(union forlan_node *p) +{ + if (!p) + return; + if (p->type > sizeof(f_tab) / sizeof(f_tab[0])) + abort(); + if (f_tab[p->type].f_free) + f_tab[p->type].f_free(p); + free(p); +} + +static void +stmt_list_free_entry(void *p) +{ + forlan_node_free(p); +} + +struct grecs_list * +forlan_stmt_list() +{ + struct grecs_list *lp; + + lp = grecs_list_create(); + lp->free_entry = stmt_list_free_entry; + return lp; +} + +union forlan_node * +forlan_stmt_from_list(struct grecs_list *list) +{ + union forlan_node **tail = NULL, *ret = NULL; + struct grecs_list_entry *ep; + + for (ep = list->head; ep; ep = ep->next) { + union forlan_node *sp = forlan_node_create(forlan_type_stmt); + sp->stmt.stmt = ep->data; + if (tail) + *tail = sp; + else + ret = sp; + tail = &sp->stmt.next; + } + list->free_entry = NULL; + grecs_list_free(list); + return ret; +} + +static void +f_dump_node(FILE *fp, union forlan_node *p, int *num, int lev) +{ + if (p) { + if (p->type > sizeof(f_tab) / sizeof(f_tab[0])) + abort(); + if (f_tab[p->type].f_dump) + f_tab[p->type].f_dump(fp, p, num, lev); + else + fprintf(fp, "type %d", p->type); + } else + fprintf(fp, "NULL"); +} + +void +forlan_dump_node(FILE *fp, union forlan_node *p, int *num, int lev) +{ + if (!p) + return; + ++*num; + fprintf(fp, "%04d: %*.*s", *num, lev, lev, ""); + f_dump_node(fp, p, num, lev); +} + +void +forlan_dump_tree(FILE *fp, union forlan_node *node) +{ + int n = 0; + forlan_dump_node(fp, node, &n, 0); +} diff --git a/lib/forlan.h b/lib/forlan.h new file mode 100644 index 0000000..4dadc70 --- /dev/null +++ b/lib/forlan.h @@ -0,0 +1,123 @@ +/* This file is part of Eclat. + Copyright (C) 2012 Sergey Poznyakoff. + + Eclat is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + Eclat is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Eclat. If not, see <http://www.gnu.org/licenses/>. */ + +#define FORLAN_DBG_LEX 3 +#define FORLAN_DBG_GRAM 2 +#define FORLAN_DBG_EVAL 1 + +extern int forlan_dbg; + +void forlan_init(); +void forlan_lex_begin(const char *input, size_t length, + struct grecs_locus_point *pt); +void forlan_lex_end(void); +int forlan_parse(const char *input, size_t length, + struct grecs_locus_point *pt); + +union forlan_node; /* Declared below */ + +enum forlan_type { + forlan_type_null, /* Unknown/unset type */ + forlan_type_comp, /* A path component */ + forlan_type_test, /* Value test (f[X]) */ + forlan_type_func, /* Function call */ + forlan_type_cond, /* Conditional */ + forlan_type_stmt, /* Statement */ + forlan_type_lit, /* Literal */ + forlan_type_expr, /* Boolean expression */ + forlan_type_last /* Return last evaluated grecs_node */ +}; + +/* A path component */ +struct forlan_node_comp { + enum forlan_type type; + int abs; + union forlan_node *node; +}; + +/* Path test: .path.comp[value] */ +struct forlan_node_test { + enum forlan_type type; + char *comp; + char *value; +}; + +/* Function call */ +struct forlan_node_func { + enum forlan_type type; + void *fp; /* FIXME: replace with typedef */ + struct grecs_list *args; /* Arguments are struct forlan_node * */ +}; + +/* Conditional */ +struct forlan_node_cond { + enum forlan_type type; + union forlan_node *expr; /* Controlling expression */ + union forlan_node *iftrue; /* Run this if expr yields true */ + union forlan_node *iffalse; /* Run this if expr yields false */ +}; + +/* Statement or statement list */ +struct forlan_node_stmt { + enum forlan_type type; + union forlan_node *stmt; + union forlan_node *next; +}; + +/* Literal string */ +struct forlan_node_lit { + enum forlan_type type; + char *string; +}; + +/* Boolean opcodes */ +enum forlan_opcode { + forlan_opcode_node, /* Evaluate node, set 'last' */ + forlan_opcode_and, /* Boolean AND */ + forlan_opcode_or, /* Boolean OR */ + forlan_opcode_not /* Boolean NOT */ +}; + +/* Boolean expression */ +struct forlan_node_expr { + enum forlan_type type; + enum forlan_opcode opcode; + union forlan_node *arg[2]; +}; + +/* Now get all this together */ +union forlan_node { + enum forlan_type type; + struct forlan_node_comp comp; /* A path component */ + struct forlan_node_test test; /* Value test (f[X]) */ + struct forlan_node_func func; /* Function call */ + struct forlan_node_cond cond; /* Conditional */ + struct forlan_node_stmt stmt; /* Statement */ + struct forlan_node_lit lit; /* Literal */ + struct forlan_node_expr expr; /* Boolean expression */ + /* forlan_type_last needs no additional data */ +}; + +union forlan_node *forlan_node_create(enum forlan_type type); +void forlan_node_free(union forlan_node *); +struct grecs_list *forlan_stmt_list(void); +struct grecs_list *forlan_complist(void); +union forlan_node *forlan_stmt_from_list(struct grecs_list *list); + +extern union forlan_node *forlan_parse_tree; + +void forlan_dump_node(FILE *fp, union forlan_node *p, int *num, int lev); +void forlan_dump_tree(FILE *fp, union forlan_node *node); diff --git a/lib/forlangrm.y b/lib/forlangrm.y new file mode 100644 index 0000000..1b7781d --- /dev/null +++ b/lib/forlangrm.y @@ -0,0 +1,237 @@ +%{ +/* This file is part of Eclat. + Copyright (C) 2012 Sergey Poznyakoff. + + Eclat is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + Eclat is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Eclat. If not, see <http://www.gnu.org/licenses/>. */ + +#include "libeclat.h" +#include <grecs.h> +#include <grecs-locus.h> +#include "forlangrm.h" +#include "forlan.h" + +static int yyerror(char *); +union forlan_node *forlan_parse_tree; +%} +%error-verbose +%locations + +%union { + char *string; + union forlan_node *node; + struct grecs_list *list; +}; + +%token <string> STRING IDENT +%token LAST IF ELSE + +%left OR +%left AND +%left NOT + +%type <node> stmt stmt_cond stmt_expr stmt_blk cond bool node comp funcall arg +%type <list> stmtlist complist arglist +%type <string> string + +%% +input : stmtlist + { + forlan_parse_tree = forlan_stmt_from_list($1); + } + ; + +stmtlist : stmt + { + $$ = forlan_stmt_list(); + grecs_list_append($$, $1); + } + | stmtlist stmt + { + grecs_list_append($1, $2); + $$ = $1; + } + ; + +stmt : stmt_cond + | stmt_expr + | stmt_blk + ; + +stmt_blk : '{' stmtlist '}' + { + $$ = forlan_stmt_from_list($2); + } + ; + +stmt_cond : IF cond stmt + { + $$ = forlan_node_create(forlan_type_cond); + $$->cond.expr = $2; + $$->cond.iftrue = $3; + $$->cond.iffalse = NULL; + } + | IF cond stmt ELSE stmt + { + $$ = forlan_node_create(forlan_type_cond); + $$->cond.expr = $2; + $$->cond.iftrue = $3; + $$->cond.iffalse = $5; + } + ; + +cond : bool + ; + +bool : node + { + $$ = forlan_node_create(forlan_type_expr); + $$->expr.opcode = forlan_opcode_node; + $$->expr.arg[0] = $1; + } + | bool AND bool + { + $$ = forlan_node_create(forlan_type_expr); + $$->expr.opcode = forlan_opcode_and; + $$->expr.arg[0] = $1; + $$->expr.arg[1] = $3; + } + | bool OR bool + { + $$ = forlan_node_create(forlan_type_expr); + $$->expr.opcode = forlan_opcode_or; + $$->expr.arg[0] = $1; + $$->expr.arg[1] = $3; + } + | NOT bool + { + $$ = forlan_node_create(forlan_type_expr); + $$->expr.opcode = forlan_opcode_not; + $$->expr.arg[0] = $2; + } + | '(' bool ')' + { + $$ = $2; + } + ; + +node : complist + { + $$ = forlan_node_create(forlan_type_comp); + $$->comp.abs = 0; + $$->comp.node = forlan_stmt_from_list($1); + } + | '.' complist + { + $$ = forlan_node_create(forlan_type_comp); + $$->comp.abs = 1; + $$->comp.node = forlan_stmt_from_list($2); + } + | LAST + { + $$ = forlan_node_create(forlan_type_last); + } + ; + +complist : comp + { + $$ = forlan_stmt_list(); + grecs_list_append($$, $1); + } + | complist '.' comp + { + grecs_list_append($1, $3); + $$ = $1; + } + ; + +comp : IDENT + { + $$ = forlan_node_create(forlan_type_lit); + $$->lit.string = $1; + } + | IDENT '[' string ']' + { + $$ = forlan_node_create(forlan_type_test); + $$->test.comp = $1; + $$->test.value = $3; + } + | funcall + ; + +string : IDENT + | STRING + ; + +funcall : IDENT '(' ')' + { + $$ = forlan_node_create(forlan_type_func); + $$->func.fp = $1; //FIXME + $$->func.args = NULL; + } + | IDENT '(' arglist ')' + { + $$ = forlan_node_create(forlan_type_func); + $$->func.fp = $1; //FIXME + $$->func.args = $3; + } + ; + +arglist : arg + { + $$ = forlan_stmt_list(); + grecs_list_append($$, $1); + } + | arglist ',' arg + { + grecs_list_append($1, $3); + $$ = $1; + } + ; + +arg : node + | STRING + { + $$ = forlan_node_create(forlan_type_lit); + $$->lit.string = $1; + } + ; + +stmt_expr : funcall ';' + ; +%% +static int +yyerror(char *s) +{ + grecs_error(&yylloc, 0, "%s", s); + return 0; +} + +int +forlan_parser() +{ + yydebug = debug_level(forlan_dbg) >= FORLAN_DBG_GRAM; + return yyparse(); +} + +int +forlan_parse(const char *input, size_t length, struct grecs_locus_point *pt) +{ + int rc; + forlan_lex_begin(input, length, pt); + rc = forlan_parser(); + forlan_lex_end(); + return rc; +} + + diff --git a/lib/forlanlex.l b/lib/forlanlex.l new file mode 100644 index 0000000..99966ed --- /dev/null +++ b/lib/forlanlex.l @@ -0,0 +1,137 @@ +%{ +/* This file is part of Eclat. + Copyright (C) 2012 Sergey Poznyakoff. + + Eclat is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + Eclat is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Eclat. If not, see <http://www.gnu.org/licenses/>. */ + +#include "libeclat.h" +#include <grecs.h> +#include <grecs-locus.h> +#include "forlangrm.h" +#include "forlan.h" + +static const char *forlan_input_base; +static size_t forlan_input_len; +static size_t forlan_input_pos; + +#undef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + do { \ + size_t __s = forlan_input_len - forlan_input_pos; \ + if (__s > max_size) \ + __s = max_size; \ + if (__s > 0) { \ + memcpy(buf, forlan_input_base, __s); \ + forlan_input_pos += __s; \ + } \ + result = __s; \ + } while(0) + +#define YY_USER_ACTION do { \ + if (YYSTATE == 0) { \ + yylloc.beg = grecs_current_locus_point; \ + yylloc.beg.col++; \ + } \ + grecs_current_locus_point.col += yyleng; \ + yylloc.end = grecs_current_locus_point; \ + } while (0); + +static int yywrap(void); + +%} + +WS [ \t\f][ \t\f]* +IDC [a-zA-Z_0-9-] +%x COMMENT ML STR +%% + /* Comments */ +"/*" BEGIN(COMMENT); +<COMMENT>[^*\n]* /* eat anything that's not a '*' */ +<COMMENT>"*"+[^*/\n]* /* eat up '*'s not followed by '/'s */ +<COMMENT>\n grecs_locus_point_advance_line(grecs_current_locus_point); +<COMMENT>"*"+"/" BEGIN(INITIAL); +"//".* ; + /* Keywords */ +if return IF; +else return ELSE; +last return LAST; +! return NOT; +"&&" return AND; +"||" return OR; +{IDC}{IDC}* { grecs_line_begin(); + grecs_line_add(yytext, yyleng); + yylval.string = grecs_line_finish(); + return IDENT; } + /* Quoted strings */ +\"[^\\"\n]*\" { grecs_line_begin(); + grecs_line_add(yytext + 1, yyleng - 2); + yylval.string = grecs_line_finish(); + return STRING; } +\"[^\\"\n]*\\\n { BEGIN(STR); + grecs_line_begin(); + grecs_line_acc_grow_unescape_last(yytext + 1, + yyleng - 1); + grecs_locus_point_advance_line(grecs_current_locus_point); } +\"[^\\"\n]*\\. { BEGIN(STR); + grecs_line_begin(); + grecs_line_acc_grow_unescape_last(yytext + 1, + yyleng - 1); } +<STR>\"[^\\"\n]*\\\n { grecs_line_acc_grow_unescape_last(yytext, yyleng); + grecs_locus_point_advance_line(grecs_current_locus_point); } +<STR>[^\\"\n]*\\. { grecs_line_acc_grow_unescape_last(yytext, yyleng); } +<STR>[^\\"\n]*\" { BEGIN(INITIAL); + if (yyleng > 1) + grecs_line_add(yytext, yyleng - 1); + yylval.string = grecs_line_finish(); + return STRING; } + /* Other tokens */ +{WS} ; +\n { grecs_locus_point_advance_line(grecs_current_locus_point); } +[.,;{}()\[\]] return yytext[0]; +. { if (isascii(yytext[0]) && isprint(yytext[0])) + grecs_error(&yylloc, 0, + _("stray character %c"), yytext[0]); + else + grecs_error(&yylloc, 0, + _("stray character \\%03o"), + (unsigned char) yytext[0]); } +%% + +static int +yywrap() +{ + return 1; +} + +void +forlan_lex_begin(const char *input, size_t length, + struct grecs_locus_point *pt) +{ + forlan_input_base = input; + forlan_input_len = length; + grecs_current_locus_point = *pt; + yy_flex_debug = debug_level(forlan_dbg) >= FORLAN_DBG_LEX; + grecs_line_acc_create(); +} + +void +forlan_lex_end() +{ + grecs_line_acc_free(); +} + + + + + diff --git a/lib/libeclat.h b/lib/libeclat.h index 670c51b..5f37cc9 100644 --- a/lib/libeclat.h +++ b/lib/libeclat.h @@ -18,6 +18,39 @@ #include <expat.h> #include "grecs.h" +extern const char *program_name; + +struct debug_category { + const char *name; + size_t length; + int level; +}; + +extern struct debug_category debug_category[]; +#define LIBECLAT_DBG_MAX 64 + +#define debug_level(cat) ((cat >= 0 && cat < LIBECLAT_DBG_MAX) ? \ + debug_category[cat].level : 0) +#define debug(cat, lev, s) \ + do { \ + if (debug_level(cat) >= (lev)) \ + debug_printf s; \ + } while(0) + +void set_program_name(const char *arg); + +void die(int status, const char *fmt, ...); +void vdiag(grecs_locus_t const *locus, const char *qual, const char *fmt, + va_list ap); +void diag(grecs_locus_t const *locus, const char *qual, const char *fmt, ...); +void err(const char *fmt, ...); +void warn(const char *fmt, ...); +void debug_printf(const char *fmt, ...); + +int parse_debug_level(const char *arg); +int debug_register(char *name); + + void hmac_sha1(const void *text, size_t textlen, const void *key, size_t keylen, void *digest); |