aboutsummaryrefslogtreecommitdiff
path: root/tools/lex.l
diff options
context:
space:
mode:
Diffstat (limited to 'tools/lex.l')
-rw-r--r--tools/lex.l773
1 files changed, 773 insertions, 0 deletions
diff --git a/tools/lex.l b/tools/lex.l
new file mode 100644
index 0000000..6706ce5
--- /dev/null
+++ b/tools/lex.l
@@ -0,0 +1,773 @@
+%{
+/* This file is part of GDBM, the GNU data base manager.
+ Copyright (C) 1990-2023 Free Software Foundation, Inc.
+
+ GDBM 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.
+
+ GDBM 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 GDBM. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "gdbmtool.h"
+#include "gram.h"
+
+struct context /* Input context */
+{
+ struct context *parent; /* Pointer to the parent context */
+ struct locus locus; /* Locus */
+ struct point point;
+ YY_BUFFER_STATE buf; /* Buffer */
+ instream_t input;
+};
+
+static struct context *context_tos;
+
+/* Advance locus to the next line */
+void
+advance_line (void)
+{
+ ++context_tos->point.line;
+ context_tos->point.col = 0;
+}
+
+static int setbeg (void);
+
+#define YY_USER_ACTION \
+ do \
+ { \
+ if (setbeg ()) \
+ { \
+ yylloc.beg = context_tos->point; \
+ yylloc.beg.col++; \
+ } \
+ context_tos->point.col += yyleng; \
+ yylloc.end = context_tos->point; \
+ } \
+ while (0);
+
+#undef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ do \
+ { \
+ if (context_tos) \
+ result = instream_read (context_tos->input, buf, max_size); \
+ else \
+ result = 0; \
+ } \
+ while (0);
+
+void string_begin (void);
+void string_add (const char *s, int l);
+void string_addc (int c);
+char *string_end (int empty_null);
+int unescape (int c);
+
+struct file_name
+{
+ struct file_name *next;
+ char str[1];
+};
+
+static struct file_name *file_head;
+
+static void
+file_names_free (void)
+{
+ while (file_head)
+ {
+ struct file_name *next = file_head->next;
+ free (file_head);
+ file_head = next;
+ }
+}
+
+char *
+file_name_alloc (char const *s)
+{
+ struct file_name *f = emalloc (sizeof (*f) + strlen (s));
+ strcpy (f->str, s);
+ f->next = file_head;
+ if (!file_head)
+ atexit (file_names_free);
+ file_head = f;
+ return f->str;
+}
+
+int
+interactive (void)
+{
+ return context_tos && instream_interactive (context_tos->input);
+}
+
+int
+input_history_size (void)
+{
+ return context_tos ? instream_history_size (context_tos->input) : 0;
+}
+
+const char *
+input_history_get (int n)
+{
+ return context_tos ? instream_history_get (context_tos->input, n) : NULL;
+}
+
+const char *
+input_stream_name (void)
+{
+ return context_tos ? context_tos->input->in_name : "NULL";
+}
+
+static struct context *
+input_context_lookup (instream_t istr)
+{
+ struct context *cp;
+
+ for (cp = context_tos; cp; cp = cp->parent)
+ if (instream_eq (cp->input, istr))
+ break;
+ return cp;
+}
+
+int
+input_context_push (instream_t input)
+{
+ struct context *cp;
+
+ cp = input_context_lookup (input);
+ if (cp)
+ {
+ terror (_("recursive sourcing"));
+ if (cp->parent)
+ lerror (&cp->locus, _("%s already sourced here"),
+ instream_name (input));
+ return 1;
+ }
+
+ yy_switch_to_buffer (yy_create_buffer (NULL, YY_BUF_SIZE));
+
+ /* Create new context */
+
+ cp = ecalloc (1, sizeof (*cp));
+ cp->locus = yylloc;
+ cp->point.file = file_name_alloc (instream_name (input));
+ cp->point.line = 1;
+ cp->point.col = 0;
+
+ cp->input = input;
+ cp->buf = YY_CURRENT_BUFFER;
+ cp->parent = context_tos;
+ context_tos = cp;
+
+ return 0;
+}
+
+void
+lex_trace (int n)
+{
+ yy_flex_debug = n;
+}
+
+int
+input_context_pop (void)
+{
+ struct context *cp;
+
+ if (!context_tos)
+ return 1;
+ instream_close (context_tos->input);
+ cp = context_tos->parent;
+ free (context_tos);
+ context_tos = cp;
+ yy_delete_buffer (YY_CURRENT_BUFFER);
+ if (!cp)
+ return 1;
+
+ yylloc = cp->locus;
+ yy_switch_to_buffer (cp->buf);
+
+ return 0;
+}
+
+void
+input_context_drain (void)
+{
+ while (!input_context_pop ())
+ ;
+}
+
+static int
+t_num (int base)
+{
+ long n;
+ errno = 0;
+ n = strtol (yytext, NULL, base);
+ if (errno)
+ {
+ lerror (&yylloc, "%s", strerror (errno));
+ return T_BOGUS;
+ }
+ if (n < INT_MIN || n > INT_MAX)
+ {
+ lerror (&yylloc, "value out of range");
+ return T_BOGUS;
+ }
+ yylval.num = n;
+ return T_NUM;
+}
+
+%}
+
+%option noinput
+%option nounput
+%option nodefault
+
+%x CMD STR MLSTR DEF SHELLWS SHELL SHSTR SHQ
+
+WS [ \t][ \t]*
+IDENT [a-zA-Z_][a-zA-Z_0-9-]*
+N [0-9][0-9]*
+P [1-9][0-9]*
+X [0-9a-fA-F]
+O [0-7]
+
+%%
+^[ \t]*#[ \t]*line[ \t].*\n {
+ char *p;
+ char *file = NULL;
+ int line, len;
+
+ for (p = strchr (yytext, '#') + 1; *p == ' ' || *p == '\t'; p++);
+ p += 4;
+ for (; *p == ' ' || *p == '\t'; p++);
+
+ line = strtol (p, &p, 10);
+ for (; *p == ' ' || *p == '\t'; p++);
+
+ if (*p == '"')
+ {
+ p++;
+ len = strcspn (p, "\"");
+ if (p[len] == 0)
+ {
+ yyerror (_("invalid #line statement"));
+ REJECT;
+ }
+ file = emalloc (len + 1);
+ memcpy (file, p, len);
+ file[len] = 0;
+ for (p += len + 1; *p == ' ' || *p == '\t'; p++);
+ }
+ if (*p != '\n' )
+ {
+ yyerror (_("invalid #line statement"));
+ free (file);
+ REJECT;
+ }
+ if (file)
+ context_tos->point.file = file;
+ context_tos->point.line = line;
+ context_tos->point.col = 0;
+}
+#.*\n advance_line ();
+#.* /* end-of-file comment */;
+
+<INITIAL>{
+\? { BEGIN (CMD);
+ return command_lookup ("help", &yylloc, &yylval.cmd); }
+\! {
+ BEGIN (SHELLWS);
+ string_begin ();
+ return command_lookup ("shell", &yylloc, &yylval.cmd);
+ }
+{IDENT} {
+ int t;
+ t = command_lookup (yytext, &yylloc, &yylval.cmd);
+ if (t == T_SHELL)
+ BEGIN (SHELLWS);
+ else
+ BEGIN (CMD);
+ return t;
+ }
+{WS} ;
+}
+
+<DEF>{
+off { return T_OFF; }
+pad { return T_PAD; }
+0[xX]{X}{X}* { return t_num (8); };
+0{O}{O}* { return t_num (16); };
+0|{P} { return t_num (10); };
+{IDENT} { if ((yylval.type = datadef_lookup (yytext)))
+ return T_TYPE;
+ else
+ {
+ yylval.string = estrdup (yytext);
+ return T_IDENT;
+ }
+ }
+[^ \"\t\n;\[\]{},=]+ { yylval.string = estrdup (yytext); return T_WORD; }
+\n { advance_line (); }
+{WS} ;
+. return yytext[0];
+}
+
+<CMD>{
+{IDENT} { yylval.string = estrdup (yytext); return T_IDENT; }
+[^ \"\t\n;\[\]{},=]+ { yylval.string = estrdup (yytext); return T_WORD; }
+\"[^\\\"\n]*\" {
+ yylval.string = emalloc (yyleng - 1);
+ memcpy (yylval.string, yytext+1, yyleng-2);
+ yylval.string[yyleng-2] = 0;
+ return T_WORD; }
+\"[^\\\"\n]*\\\n {
+ advance_line ();
+ string_begin ();
+ string_add (yytext + 1, yyleng - 2);
+ BEGIN (MLSTR); }
+\"[^\\\"\n]*\\. {
+ string_begin ();
+ string_add (yytext + 1, yyleng - 3);
+ string_addc (unescape (yytext[yyleng-1]));
+ BEGIN (STR); }
+; { BEGIN (INITIAL); return ';'; }
+{WS} ;
+}
+
+<STR,MLSTR>{
+[^\\\"\n]*\" { if (yyleng > 1)
+ string_add (yytext, yyleng - 1);
+ yylval.string = string_end (FALSE);
+ BEGIN (CMD);
+ return T_WORD; }
+[^\\\"\n]*\\\n { advance_line ();
+ string_add (yytext, yyleng - 1); }
+[^\\\"\n]*\\. { string_add (yytext, yyleng - 2);
+ string_addc (unescape (yytext[yyleng-1])); }
+}
+
+<SHELLWS>{
+{WS} { BEGIN(SHELL); }
+"\n" {
+ BEGIN (INITIAL);
+ advance_line ();
+ return '\n';
+ }
+}
+
+<SHELL>{
+\\\n { advance_line (); string_add (yytext, yyleng); }
+\\. { string_add (yytext, yyleng); }
+\'[^\'\n]*\' { string_add (yytext, yyleng); }
+\'[^\'\n]*\n { advance_line ();
+ string_add (yytext, yyleng);
+ BEGIN (SHQ); }
+\"[^\\\"\n]*\" { string_add (yytext, yyleng); }
+\"[^\\\"\n]*\n { advance_line ();
+ string_add (yytext, yyleng);
+ BEGIN (SHSTR); }
+\"[^\\\"\n]*\\. { string_add (yytext, yyleng);
+ BEGIN (SHSTR); }
+"\n" {
+ BEGIN (INITIAL);
+ advance_line ();
+ yyless (0);
+ if ((yylval.string = string_end (TRUE)) != NULL)
+ return T_WORD;
+ }
+. string_addc (yytext[0]);
+}
+
+<SHSTR>{
+[^\\\"]*\\. { string_add (yytext, yyleng); }
+[^\\\"]*\" { string_add (yytext, yyleng);
+ BEGIN (SHELL); }
+}
+
+<SHQ>{
+[^\'\n]*\n { advance_line ();
+ string_add (yytext, yyleng); }
+[^\'\n]*\' { string_add (yytext, yyleng);
+ BEGIN (SHELL); }
+}
+
+<*>\n { BEGIN (INITIAL); advance_line (); return '\n'; }
+
+<INITIAL,CMD,DEF>. return yytext[0];
+%%
+
+int
+yywrap (void)
+{
+ return input_context_pop ();
+}
+
+void
+begin_def (void)
+{
+ BEGIN (DEF);
+}
+
+void
+end_def (void)
+{
+ BEGIN (CMD);
+}
+
+void
+print_prompt_at_bol (void)
+{
+ if (YY_AT_BOL ())
+ {
+ char *s = make_prompt ();
+ fputs (s, stdout);
+ fflush (stdout);
+ free (s);
+ }
+}
+
+
+struct strseg
+{
+ struct strseg *next;
+ int len;
+ char ptr[1];
+};
+
+static struct strseg *strseg_head, *strseg_tail;
+
+void
+string_begin (void)
+{
+ strseg_head = strseg_tail = NULL;
+}
+
+void
+strseg_attach (struct strseg *seg)
+{
+ seg->next = NULL;
+ if (strseg_tail)
+ strseg_tail->next = seg;
+ else
+ strseg_head = seg;
+ strseg_tail = seg;
+}
+
+void
+string_add (const char *s, int l)
+{
+ struct strseg *seg = emalloc (sizeof (*seg) + l);
+ memcpy (seg->ptr, s, l);
+ seg->len = l;
+ strseg_attach (seg);
+}
+
+void
+string_addc (int c)
+{
+ struct strseg *seg = emalloc (sizeof (*seg));
+ seg->ptr[0] = c;
+ seg->len = 1;
+ strseg_attach (seg);
+}
+
+/*
+ * Compose the collected string segments into a nul-terminated string.
+ * Return the allocated string.
+ * If EMPTY_NULL is TRUE and the resulting string length is 0, return
+ * NULL instead.
+ */
+char *
+string_end (int empty_null)
+{
+ int len = 0;
+ struct strseg *seg;
+ char *ret, *p;
+
+ for (seg = strseg_head; seg; seg = seg->next)
+ len += seg->len;
+
+ if (len == 0 && empty_null)
+ ret = NULL;
+ else
+ {
+ ret = emalloc (len + 1);
+ p = ret;
+ for (seg = strseg_head; seg; )
+ {
+ struct strseg *next = seg->next;
+ memcpy (p, seg->ptr, seg->len);
+ p += seg->len;
+ free (seg);
+ seg = next;
+ }
+ *p = 0;
+ }
+ strseg_head = strseg_tail = NULL;
+
+ return ret;
+}
+
+static char transtab[] = "\\\\\"\"a\ab\bf\fn\nr\rt\tv\v";
+
+int
+unescape (int c)
+{
+ char *p;
+
+ for (p = transtab; *p; p += 2)
+ {
+ if (*p == c)
+ return p[1];
+ }
+ return c;
+}
+
+int
+escape (int c)
+{
+ char *p;
+ for (p = transtab + sizeof (transtab) - 2; p > transtab; p -= 2)
+ {
+ if (*p == c)
+ return p[-1];
+ }
+ return 0;
+}
+
+void
+locus_print (FILE *fp, struct locus const *loc)
+{
+ if (loc->beg.file)
+ {
+ if (loc->beg.col == 0)
+ fprintf (fp, "%s:%u",
+ loc->beg.file,
+ loc->beg.line);
+ else if (strcmp (loc->beg.file, loc->end.file))
+ fprintf (fp, "%s:%u.%u-%s:%u.%u",
+ loc->beg.file,
+ loc->beg.line, loc->beg.col,
+ loc->end.file,
+ loc->end.line, loc->end.col);
+ else if (loc->beg.line != loc->end.line)
+ fprintf (fp, "%s:%u.%u-%u.%u",
+ loc->beg.file,
+ loc->beg.line, loc->beg.col,
+ loc->end.line, loc->end.col);
+ else if (loc->beg.col != loc->end.col)
+ fprintf (fp, "%s:%u.%u-%u",
+ loc->beg.file,
+ loc->beg.line, loc->beg.col,
+ loc->end.col);
+ else
+ fprintf (fp, "%s:%u.%u",
+ loc->beg.file,
+ loc->beg.line,
+ loc->beg.col);
+ }
+}
+
+void
+vlerror (struct locus *loc, const char *fmt, va_list ap)
+{
+ if (!interactive ())
+ fprintf (stderr, "%s: ", progname);
+ if (loc && loc->beg.file)
+ {
+ YY_LOCATION_PRINT (stderr, *loc);
+ fprintf (stderr, ": ");
+ }
+ vfprintf (stderr, fmt, ap);
+ fputc ('\n', stderr);
+}
+
+void
+lerror (struct locus *loc, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start (ap, fmt);
+ vlerror (loc, fmt, ap);
+ va_end (ap);
+}
+
+
+static struct slist *
+pe_file_name (void)
+{
+ char *name = NULL;
+ variable_get ("filename", VART_STRING, (void**) &name);
+ return name ? slist_new (name) : NULL;
+}
+
+static struct slist *
+pe_program_name (void)
+{
+ return slist_new (progname);
+}
+
+static struct slist *
+pe_package_name (void)
+{
+ return slist_new (PACKAGE_NAME);
+}
+
+static struct slist *
+pe_program_version (void)
+{
+ return slist_new (PACKAGE_VERSION);
+}
+
+static struct slist *
+pe_space (void)
+{
+ return slist_new (" ");
+}
+
+struct prompt_exp
+{
+ int ch;
+ struct slist *(*fun) (void);
+};
+
+struct prompt_exp prompt_exp[] = {
+ { 'f', pe_file_name },
+ { 'p', pe_program_name },
+ { 'P', pe_package_name },
+ { 'v', pe_program_version },
+ { '_', pe_space },
+ { 0 }
+};
+
+static int
+expand_char (int c, struct slist **tailp)
+{
+ struct prompt_exp *p;
+
+ if (c && c != '%')
+ {
+ for (p = prompt_exp; p->ch; p++)
+ {
+ if (c == p->ch)
+ {
+ struct slist *s = p->fun ();
+ if (s)
+ slist_insert (tailp, s);
+ return 0;
+ }
+ }
+ }
+ return 1;
+}
+
+char const *
+psname (void)
+{
+ switch (YYSTATE)
+ {
+ case DEF:
+ case MLSTR:
+ case SHSTR:
+ case SHQ:
+ return "ps2";
+
+ default:
+ return "ps1";
+ }
+}
+
+static int
+setbeg (void)
+{
+ switch (YYSTATE)
+ {
+ case INITIAL:
+ case CMD:
+ case SHELL:
+ case DEF:
+ return 1;
+
+ default:
+ /* STR MLSTR SHELLWS SHSTR SHQ */
+ return 0;
+ }
+}
+
+char *
+make_prompt (void)
+{
+ const char *s;
+ const char *prompt;
+ struct slist *head = NULL, *tail = NULL, *p;
+ char *ret, *end;
+ size_t len;
+
+ switch (variable_get (psname (), VART_STRING, (void *) &prompt))
+ {
+ case VAR_OK:
+ break;
+
+ case VAR_ERR_NOTSET:
+ return NULL;
+
+ default:
+ abort ();
+ }
+
+ for (s = prompt; *s; )
+ {
+ if (*s == '%' && s[1])
+ {
+ if (s > prompt)
+ {
+ slist_insert (&tail, slist_new_l (prompt, s - prompt));
+ if (!head)
+ head = tail;
+ }
+ if (expand_char (s[1], &tail) == 0)
+ {
+ if (!head)
+ head = tail;
+ prompt = s + 2;
+ }
+ else
+ prompt = s;
+ s += 2;
+ }
+ else
+ ++s;
+ }
+
+ if (s > prompt)
+ {
+ slist_insert (&tail, slist_new_l (prompt, s - prompt));
+ if (!head)
+ head = tail;
+ }
+
+ len = 0;
+ for (p = head; p; p = p->next)
+ len += strlen (p->str);
+
+ ret = emalloc (len + 1);
+ end = ret;
+ for (p = head; p; p = p->next)
+ {
+ s = p->str;
+ while (*s)
+ *end++ = *s++;
+ }
+ *end = 0;
+
+ slist_free (head);
+
+ return ret;
+}
+

Return to:

Send suggestions and report system problems to the System administrator.