diff options
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | am/grecs.m4 | 7 | ||||
-rwxr-xr-x | build-aux/yyrename | 92 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | doc/GRECS_SETUP.3 | 8 | ||||
-rw-r--r-- | doc/grecs_parse.3 | 8 | ||||
-rw-r--r-- | src/.gitignore | 4 | ||||
-rw-r--r-- | src/Make.am | 19 | ||||
-rw-r--r-- | src/asprintf.c | 85 | ||||
-rw-r--r-- | src/grecs-gram.y | 80 | ||||
-rw-r--r-- | src/grecs-lex.l | 133 | ||||
-rw-r--r-- | src/grecs.h | 35 | ||||
-rw-r--r-- | src/lineacc.c | 82 | ||||
-rw-r--r-- | src/meta1-gram.y | 217 | ||||
-rw-r--r-- | src/meta1-lex.l | 114 | ||||
-rw-r--r-- | src/parser.c | 60 | ||||
-rw-r--r-- | src/txtacc.c | 187 | ||||
-rw-r--r-- | src/wordsplit.c | 2 | ||||
-rw-r--r-- | src/yygrecs.h | 28 | ||||
-rw-r--r-- | src/yytrans | 20 |
20 files changed, 944 insertions, 241 deletions
diff --git a/Makefile.am b/Makefile.am index d614a25..0696c72 100644 --- a/Makefile.am +++ b/Makefile.am @@ -7,25 +7,25 @@ # any later version. # # Grecs 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 Grecs. If not, see <http://www.gnu.org/licenses/>. ACLOCAL_AMFLAGS = -I am SUBDIRS=. src @GRECS_TESTDIR@ @GRECS_DOCDIR@ -EXTRA_DIST=@GRECS_BUILD_AUX@ gitid.h +EXTRA_DIST=build-aux/yyrename @GRECS_BUILD_AUX@ gitid.h noinst_HEADERS = gitid.h BUILT_SOURCES = gitid.h README .PHONY: gitid.h gitid.h: @if test -d .git; then \ url=`git config --get remote.origin.url | sed 's|.*://||;s|/gitroot/|/|'`; \ if test "$$url" = "git.gnu.org.ua/grecs.git"; then \ dirty=`git diff-index --name-only HEAD 2>/dev/null` || dirty=;\ test -n "$$dirty" && dirty="-dirty"; \ ID=`git log -1 --pretty='%H-%ct-%ae'`$$dirty;\ diff --git a/am/grecs.m4 b/am/grecs.m4 index 0d1b03d..8f4868b 100644 --- a/am/grecs.m4 +++ b/am/grecs.m4 @@ -139,36 +139,41 @@ AC_DEFUN([GRECS_SETUP],[ AC_CONFIG_TESTDIR(TESTDIR) AC_CONFIG_FILES(TESTDIR/Makefile TESTDIR/atlocal) m4_popdef([TESTDIR]) AM_MISSING_PROG([AUTOM4TE], [autom4te]) GRECS_TESTDIR=tests ]) _GRECS_IF_OPTION_SET([getopt],[ AC_CHECK_HEADERS([getopt.h]) AC_CHECK_FUNCS([sysconf getdtablesize getopt_long]) GRECS_BUILD_AUX="build-aux/getopt.m4" ]) _GRECS_IF_OPTION_SET([git2chg],[GRECS_BUILD_AUX="$GRECS_BUILD_AUX build-aux/git2chg.awk"]) - + AM_CONDITIONAL([GRECS_COND_META1_PARSER], + _GRECS_OPTION_SWITCH([parser-meta1],[true], + [all-parsers],[true], + [false])) + AC_SUBST([GRECS_SRCDIR],$1) AC_SUBST([GRECS_BUILD_AUX]) AC_SUBST([GRECS_INCLUDES]) AC_SUBST([GRECS_TESTDIR]) AC_SUBST([GRECS_LDADD]) AC_SUBST([GRECS_DOCDIR]) AC_SUBST([GRECS_CHANGELOG]) AC_SUBST([GRECS_DISTCK_AT]) AC_SUBST([GRECS_README]) AC_SUBST([GRECS_INCLUDES],['-I$(top_srcdir)/]grecsdir[src]') AC_SUBST([GRECS_HOST_PROJECT_INCLUDES]) + _GRECS_OPTION_SWITCH([install],[ LT_INIT GRECS_LDADD=['$(top_builddir)/]grecsdir[src/libgrecs.la'] GRECS_DOCDIR='doc' GRECS_CHANGELOG= GRECS_DISTCK_AT=distck.at GRECS_README=README.standalone AC_CONFIG_FILES(grecsdir[src/Makefile]:grecsdir[src/Make-inst.in] grecsdir[doc/Makefile]) ],[shared],[ LT_INIT GRECS_LDADD=['$(top_builddir)/]grecsdir[src/libgrecs.la'] diff --git a/build-aux/yyrename b/build-aux/yyrename new file mode 100755 index 0000000..5e7b1db --- /dev/null +++ b/build-aux/yyrename @@ -0,0 +1,92 @@ +#! /bin/sh +# Rename yy.* identifiers to avoid name clashes. This file is part of Grecs. +# Copyright (C) 2011 Sergey Poznyakoff +# +# Grecs 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. +# +# Grecs 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 Grecs. If not, see <http://www.gnu.org/licenses/>. + +# Usage: yyrename [-f OUTFILE [OUTFILE...]] COMMAND INFILE +# Makefile.am: +# LEXCOMPILE = yyrename -f $(LEX_OUTPUT_ROOT).c \ +# '$(LEX) $(LFLAGS) $(AM_LFLAGS)' +# YACCCOMPILE = yyrename '$(YACC) $(YFLAGS) $(AM_YFLAGS)' +# +# This script runs COMMAND with INFILE as its argument and scans +# OUTFILEs for identifiers starting with 'yy'. These identifiers +# are renamed by replacing 'yy' with the selected prefix. +# +# The prefix is looked up in the file yytrans, located in the INFILE's +# directory. If this file does not exist, the prefix is constructed +# by concatenating the string 'grecs_' and the ``root name''. The root +# name is build by removing '-lex.l' or '-gram.y' from the base name. +# If the latter does not end in any of these, the root name +# is constructed by removing the suffix from the base name. +# +# The yytrans file is a line-oriented lookup table. Empty lines are +# ignored, usual UNIX comment lines are honored. The remaining lines +# must consist of two words separated by any amount of whitespace. +# The first word is a look-up key, the second one provides a translation +# (yy replacement) for that key. +# +# Two look-ups are tried: first the base name and then the root name. +# If both result in a non-empty replacement, the former is preferred +# over the latter. +# +# The -f option supplies a list of output file names generated by COMMAND. +# If not supplied, the following defaults are used: y.tab.c and y.tab.h, if +# INFILE ends in '.y', and yy.lex.c, if it ends in '.l'. If INFILE does not +# end in any of these suffixes, error is reported. +# +# BUGS: Any occurrence of 'yy' is replaced, not only 'yy' prefixes. +# +case $1 in +-f) files=$2 + shift + shift +esac + +base=`expr "$2" : '.*/\(.*\)\.[ly]'` +dir=`dirname "$2"` +case $2 in +*.y) test -z "$files" && files="y.tab.c y.tab.h" + root=`expr "$2" : '.*/\(.*\)-gram\.y'`;; +*.l) test -z "$files" && files=lex.yy.c + root=`expr "$2" : '.*/\(.*\)-lex\.l'`;; +*) if test -z "$files"; then + echo >&2 "$0: suffix unknown, files must be given (use -f)" + exit 1 + fi + root=$base +esac + +if test -f $dir/yytrans; then + pfx=`awk ' +{ sub(/#.*$/,"") } +NF == 2 && $1=="'$base'" { exact=$2 } +NF == 2 && $1=="'$root'" { root=$2 } +{ next } +END { print exact ? exact : root ? root : "" }' $dir/yytrans` +else + pfx= +fi +if test -z "$pfx"; then + pfx=grecs_`echo $root | tr .- __` +fi + +eval $* || exit $? + +for file in $files +do + mv $file ${file}.tmp + sed "s/yy/$pfx/g" ${file}.tmp > $file +done diff --git a/configure.ac b/configure.ac index 980c713..816de11 100644 --- a/configure.ac +++ b/configure.ac @@ -28,15 +28,15 @@ AM_SILENT_RULES([yes]) # Checks for programs. AC_PROG_CC # Checks for libraries. # Checks for header files. AC_HEADER_STDC # Checks for library functions. # Grecs subsystem -GRECS_SETUP(., [install tests git2chg]) +GRECS_SETUP(., [install tests git2chg all-parsers]) AC_OUTPUT diff --git a/doc/GRECS_SETUP.3 b/doc/GRECS_SETUP.3 index c24399e..13b568e 100644 --- a/doc/GRECS_SETUP.3 +++ b/doc/GRECS_SETUP.3 @@ -5,25 +5,25 @@ .\" 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. .\" .\" Grecs 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 Grecs. If not, see <http://www.gnu.org/licenses/>. .\" -.TH GRECS_SETUP 3 "May 8, 2011" "GRECS" "Grecs User Reference" +.TH GRECS_SETUP 3 "May 15, 2011" "GRECS" "Grecs User Reference" .SH NAME GRECS_SETUP \- Initialize \fBgrecs\fR submodule. .SH SYNOPSIS .BI "GRECS_SETUP(" "dir" ", " "options" ", " "pp-setup-file" ) .SH DESCRIPTION The \fBGRECS_SETUP\fR macro is invoked from the host project's \fBconfigure.ac\fR. It initializes the \fBgrecs\fR submodule variables for compilation within that project. .PP All arguments are optional. .PP The @@ -35,24 +35,30 @@ For example, if \fBgrecs\fR was cloned using the following command: .sp .nf git clone ssh://git.gnu.org.ua/gitroot/grecs.git lib/grecs .fi .sp then the \fIdir\fR argument must be \fBlib/grecs\fR. .PP The .I options argument is a space-separated list of options. The following options are understood: .TP +.B all-parsers +Compile all available parsers. +.TP +.B parser-meta1 +Build the parser for MeTA1 configuration files. +.TP .B no-preproc Disable the use of preprocessor. .TP .B install Create and install shared library \fBlibgrecs.so\fR. Install the documentation as well. .TP .B shared Create a shared convenience library. By default, a static library is created. Use this option if you want to incorporate grecs into another shared library. .TP diff --git a/doc/grecs_parse.3 b/doc/grecs_parse.3 index 2abc417..dff6759 100644 --- a/doc/grecs_parse.3 +++ b/doc/grecs_parse.3 @@ -140,31 +140,29 @@ The array itself is stored in \fBv.arg.v\fR. The \fBv.arg.c\fR member contains the number of elements in the array. .SH RETURN VALUE On success, a pointer to the root node. On error, \fBNULL\fR. .SH EXAMPLE The following program parses the file and prints its contents on screen: .sp .nf .in +5 int main(int argc, char **argv) { - struct grecs_node *tree, *node; + struct grecs_node *tree; tree = grecs_parse(argv[1]); - for (node = tree; node; node = node->next) { - grecs_format_node(node, GRECS_NODE_FLAG_DEFAULT, stdout); - fputc('\n', stdout); - } + grecs_format_node(tree, GRECS_NODE_FLAG_DEFAULT, stdout); + fputc('\\n', stdout); grecs_tree_free(tree); exit(0); } .in .fi .SH "SEE ALSO" .BR grecs_config (5), .BR grecs_error (3), .BR grecs_format_node (3), .BR grecs_tree_free (3). .SH AUTHORS Sergey Poznyakoff diff --git a/src/.gitignore b/src/.gitignore index 9ef1b57..feb5040 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -1,7 +1,11 @@ grecs-gram.c grecs-gram.h grecs-gram.output grecs-lex.c +meta1-gram.c +meta1-gram.h +meta1-gram.output +meta1-lex.c Make-inst.in Make-shared.in Make-static.in diff --git a/src/Make.am b/src/Make.am index 915e6c4..60c0f06 100644 --- a/src/Make.am +++ b/src/Make.am @@ -5,39 +5,52 @@ # 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. # # Grecs 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 Grecs. If not, see <http://www.gnu.org/licenses/>. +if GRECS_COND_META1_PARSER + GRECS_PARSER_META1 = meta1-gram.y meta1-lex.l + GRECS_EXTRA_META1 = meta1-gram.h +endif + GRECS_SRC = \ + asprintf.c\ diag.c\ format.c\ grecs-gram.y\ grecs-lex.l\ join.c\ + lineacc.c\ list.c\ lookup.c\ mem.c\ + parser.c\ preproc.c\ sort.c\ symtab.c\ text.c\ tree.c\ + txtacc.c\ version.c\ - wordsplit.c + wordsplit.c\ + $(GRECS_PARSER_META1) -noinst_HEADERS = yygrecs.h +noinst_HEADERS = -EXTRA_DIST=grecs-gram.h $(PP_SETUP_FILE) Make.am Make-inst.am Make-shared.am Make-static.am +EXTRA_DIST=grecs-gram.h $(GRECS_EXTRA_META1) $(PP_SETUP_FILE) Make.am Make-inst.am Make-shared.am Make-static.am INCLUDES = -I$(srcdir) -I$(top_srcdir)/@GRECS_SUBDIR@ @GRECS_INCLUDES@ @GRECS_HOST_PROJECT_INCLUDES@ AM_YFLAGS = -dtv AM_LFLAGS = -d incdir=$(pkgdatadir)/$(VERSION)/include inc_DATA = $(PP_SETUP_FILE) + +LEXCOMPILE = $(top_srcdir)/@GRECS_SUBDIR@/build-aux/yyrename '$(LEX) $(LFLAGS) $(AM_LFLAGS)' +YACCCOMPILE = $(top_srcdir)/@GRECS_SUBDIR@/build-aux/yyrename '$(YACC) $(YFLAGS) $(AM_YFLAGS)'
\ No newline at end of file diff --git a/src/asprintf.c b/src/asprintf.c new file mode 100644 index 0000000..d493fcb --- /dev/null +++ b/src/asprintf.c @@ -0,0 +1,85 @@ +/* grecs - Gray's Extensible Configuration System + Copyright (C) 2007-2011 Sergey Poznyakoff + + Grecs 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 of the License, or (at your + option) any later version. + + Grecs 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 Grecs. If not, see <http://www.gnu.org/licenses/>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include "grecs.h" + +int +grecs_vasprintf(char **pbuf, size_t *psize, const char *fmt, va_list ap) +{ + char *buf = *pbuf; + size_t buflen = *psize; + int rc = 0; + + if (!buf) { + if (buflen == 0) + buflen = 512; /* Initial allocation */ + + buf = calloc(1, buflen); + if (buf == NULL) + return ENOMEM; + } + + for (;;) { + ssize_t n = vsnprintf(buf, buflen, fmt, ap); + if (n < 0 || n >= buflen || !memchr(buf, '\0', n + 1)) { + char *newbuf; + size_t newlen = buflen * 2; + if (newlen < buflen) { + rc = ENOMEM; + break; + } + newbuf = realloc(buf, newlen); + if (newbuf == NULL) { + rc = ENOMEM; + break; + } + buflen = newlen; + buf = newbuf; + } else + break; + } + + if (rc) { + if (!*pbuf) { + /* We made first allocation, now free it */ + free(buf); + buf = NULL; + buflen = 0; + } + } + + *pbuf = buf; + *psize = buflen; + return rc; +} + +int +grecs_asprintf(char **pbuf, size_t *psize, const char *fmt, ...) +{ + int rc; + va_list ap; + + va_start(ap, fmt); + rc = grecs_vasprintf(pbuf, psize, fmt, ap); + va_end(ap); + return rc; +} diff --git a/src/grecs-gram.y b/src/grecs-gram.y index 9f8d000..3452074 100644 --- a/src/grecs-gram.y +++ b/src/grecs-gram.y @@ -9,37 +9,35 @@ Grecs 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 Grecs. If not, see <http://www.gnu.org/licenses/>. */ #ifdef HAVE_CONFIG_H # include <config.h> #endif -#include "yygrecs.h" #include <grecs.h> #include <grecs-gram.h> #include <stdlib.h> #include <stdarg.h> #include <string.h> #include <errno.h> -static struct grecs_node *parse_tree; -int grecs_error_count; - -int grecs_default_port = 0; +int yylex(void); +int yyerror(char *s); +static struct grecs_node *parse_tree; %} %union { struct { grecs_locus_t locus; char *string; } ident; char *string; grecs_value_t svalue, *pvalue; struct grecs_list *list; struct grecs_node *node; grecs_locus_t locus; @@ -230,102 +228,36 @@ opt_sc : /* empty */ | ';' ; %% int yyerror(char *s) { grecs_error(&grecs_current_locus, 0, "%s", s); return 0; } -int -grecs_vasprintf(char **pbuf, size_t *psize, const char *fmt, va_list ap) -{ - char *buf = *pbuf; - size_t buflen = *psize; - int rc = 0; - - if (!buf) { - if (buflen == 0) - buflen = 512; /* Initial allocation */ - - buf = calloc(1, buflen); - if (buf == NULL) - return ENOMEM; - } - - for (;;) { - ssize_t n = vsnprintf(buf, buflen, fmt, ap); - if (n < 0 || n >= buflen || !memchr(buf, '\0', n + 1)) { - char *newbuf; - size_t newlen = buflen * 2; - if (newlen < buflen) { - rc = ENOMEM; - break; - } - newbuf = realloc(buf, newlen); - if (newbuf == NULL) { - rc = ENOMEM; - break; - } - buflen = newlen; - buf = newbuf; - } else - break; - } - - if (rc) { - if (!*pbuf) { - /* We made first allocation, now free it */ - free(buf); - buf = NULL; - buflen = 0; - } - } - - *pbuf = buf; - *psize = buflen; - return rc; -} - -int -grecs_asprintf(char **pbuf, size_t *psize, const char *fmt, ...) -{ - int rc; - va_list ap; - - va_start(ap, fmt); - rc = grecs_vasprintf(pbuf, psize, fmt, ap); - va_end(ap); - return rc; -} - struct grecs_node * -grecs_parse(const char *name) +grecs_grecs_parser(const char *name, int traceflags) { int rc; - if (grecs_lex_begin(name)) + if (grecs_lex_begin(name, traceflags & GRECS_TRACE_LEX)) return NULL; + yydebug = traceflags & GRECS_TRACE_GRAM; parse_tree = NULL; rc = yyparse(); if (grecs_error_count) rc = 1; grecs_lex_end(rc); if (rc) { grecs_tree_free(parse_tree); parse_tree = NULL; } return parse_tree; } -void -grecs_gram_trace(int n) -{ - yydebug = n; -} diff --git a/src/grecs-lex.l b/src/grecs-lex.l index 4d491fe..84ee858 100644 --- a/src/grecs-lex.l +++ b/src/grecs-lex.l @@ -1,18 +1,17 @@ /* grecs - Gray's Extensible Configuration System -*- c -*- */ %top { #ifdef HAVE_CONFIG_H # include <config.h> #endif -#include "yygrecs.h" } %{ /* grecs - Gray's Extensible Configuration System Copyright (C) 2007-2011 Sergey Poznyakoff Grecs 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 of the License, or (at your option) any later version. Grecs is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -39,30 +38,27 @@ static int (*char_to_strip)(char); /* Strip matching characters of each here-document line */ grecs_locus_t grecs_current_locus; /* Input file location */ /* Line correction. Equals to the number of #line directives inserted into the input by the preprocessor instance. The external preprocessor, if any, counts these as input lines and therefore the line numbers in *its* #line directives are offset by the value of XLINES. Uff, running two preprocessors is confusing... */ static size_t xlines; -static struct grecs_list *line_acc; - static void multiline_begin(char *); static void multiline_add(char *); static char *multiline_strip_tabs(char *text); -static void line_add_unescape_last(char *text, size_t len); static int ident(void); static int isemptystr(int off); static void parse_line(char *text, grecs_locus_t *ploc, size_t *pxlines); static void parse_line_cpp(char *text, grecs_locus_t *ploc, size_t *pxlines); #undef YY_INPUT #define YY_INPUT(buf,result,max_size) \ do \ { \ if (grecs_preprocessor) \ result = fread(buf, 1, max_size, yyin); \ @@ -104,27 +100,28 @@ P [1-9][0-9]* [a-zA-Z0-9_\.\*/:@-]+ { grecs_line_begin(); grecs_line_add(yytext, yyleng); yylval.string = grecs_line_finish(); return STRING; } /* Quoted strings */ \"[^\\"\n]*\" { grecs_line_begin(); grecs_line_add(yytext + 1, yyleng - 2); yylval.string = grecs_line_finish(); return QSTRING; } \"[^\\"\n]*\\. | \"[^\\"\n]*\\\n { BEGIN(STR); grecs_line_begin(); - line_add_unescape_last(yytext + 1, yyleng - 1); } + grecs_line_acc_grow_unescape_last(yytext + 1, + yyleng - 1); } <STR>[^\\"\n]*\\. | -<STR>\"[^\\"\n]*\\\n { line_add_unescape_last(yytext, yyleng); } +<STR>\"[^\\"\n]*\\\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 QSTRING; } /* Multiline strings */ "<<"(-" "?)?\\?{ID}[ \t]*#.*\n | "<<"(-" "?)?\\?{ID}[ \t]*"//".*\n | "<<"(-" "?)?\\?{ID}[ \t]*\n | "<<"(-" "?)?\"{ID}\"[ \t]*#.*\n | "<<"(-" "?)?\"{ID}\"[ \t]*"//".*\n | "<<"(-" "?)?\"{ID}\"[ \t]*\n { @@ -161,38 +158,30 @@ pid_t grecs_preproc_pid; int yywrap() { if (yyin) grecs_preproc_extrn_shutdown(grecs_preproc_pid); else grecs_preproc_done(); grecs_current_locus.file = NULL; return 1; } -static void -line_acc_free_entry(void *ptr) -{ - grecs_free(ptr); -} - int -grecs_lex_begin(const char *name) +grecs_lex_begin(const char *name, int trace) { - if (yy_flex_debug > 0) - yy_flex_debug = 0; + yy_flex_debug = trace; - line_acc = grecs_list_create(); - line_acc->free_entry = line_acc_free_entry; + grecs_line_acc_create(); if (grecs_preprocessor) { int fd; fd = open(name, O_RDONLY); if (fd == -1) { grecs_error(NULL, errno, _("Cannot open `%s'"), name); return 1; } close(fd); yyin = grecs_preproc_extrn_start(name, &grecs_preproc_pid); @@ -202,25 +191,25 @@ grecs_lex_begin(const char *name) grecs_preprocessor); return 1; } } else return grecs_preproc_init(name); return 0; } void grecs_lex_end(int err) { - grecs_list_clear(line_acc); + grecs_line_acc_free(); } static int isemptystr(int off) { for (; yytext[off] && isspace(yytext[off]); off++) ; if (yytext[off] == ';') { int i; for (i = off + 1; yytext[i]; i++) if (!isspace(yytext[i])) return 0; @@ -230,113 +219,39 @@ isemptystr(int off) return yytext[off] == 0; } char * multiline_strip_tabs(char *text) { if (char_to_strip) for (; *text && char_to_strip(*text); text++) ; return text; } -static int -unquote_char(int c) -{ - static char quote_transtab[] = "\\\\\"\"a\ab\bf\fn\nr\rt\tv\v"; - - char *p; - - for (p = quote_transtab; *p; p += 2) { - if (*p == c) - return p[1]; - } - return -1; -} - -struct line_acc_entry -{ - size_t size; -}; -#define line_acc_ptr(entry) (char*)(entry + 1) - -static void -line_acc_add_string(const char *str, size_t len) -{ - struct line_acc_entry *ent = grecs_malloc(sizeof(*ent) + len + 1); - char *p = line_acc_ptr(ent); - memcpy(p, str, len); - p[len] = 0; - ent->size = len; - grecs_list_append(line_acc, ent); -} - -static void -line_acc_add_char(int c) -{ - char t = c; - line_acc_add_string(&t, 1); -} - -static void -list_acc_unescape_char(int c) -{ - if (c != '\n') { - int t = unquote_char(c); - if (t != -1) - line_acc_add_char(t); - else { - grecs_warning(&grecs_current_locus, 0, - _("unknown escape sequence '\\%c'"), - c); - line_acc_add_char(c); - } - } -} - -void -grecs_line_add(const char *text, size_t len) -{ - line_acc_add_string(text, len); -} - -/* Same, but unescapes the last character from yytext */ -static void -line_add_unescape_last(char *text, size_t len) -{ - line_acc_add_string(text, len - 2); - list_acc_unescape_char(text[len - 1]); -} - static void multiline_add(char *s) { if (multiline_unescape) { for (; *s; s++) { if (*s == '\\') { - list_acc_unescape_char(s[1]); + grecs_line_acc_grow_char_unescape(s[1]); ++s; } else - line_acc_add_char(*s); + grecs_line_acc_grow_char(*s); } } else grecs_line_add(s, strlen(s)); } -void -grecs_line_begin() -{ - /* FIXME: nothing so far. Maybe prepare stk by calling obstack_finish? */ -} - static int is_tab(char c) { return c == '\t'; } static int is_ws(char c) { return c == '\t' || c == ' '; } @@ -365,72 +280,42 @@ multiline_begin(char *p) multiline_delimiter_len = strcspn(p, " \t"); multiline_unescape = 1; } /* Remove trailing newline */ multiline_delimiter_len--; multiline_delimiter = grecs_malloc(multiline_delimiter_len + 1); memcpy(multiline_delimiter, p, multiline_delimiter_len); multiline_delimiter[multiline_delimiter_len] = 0; grecs_line_begin(); } -char * -grecs_line_finish() -{ - struct grecs_list_entry *ep; - size_t size = 0; - char *str, *p; - - for (ep = line_acc->head; ep; ep = ep->next) { - struct line_acc_entry *ent = ep->data; - size += ent->size; - } - - str = grecs_malloc(size + 1); - for (ep = line_acc->head, p = str; ep; ep = ep->next) { - struct line_acc_entry *ent = ep->data; - char *str = line_acc_ptr(ent); - memcpy(p, str, ent->size); - p += ent->size; - } - *p = 0; - grecs_list_clear(line_acc); - return str; -} - static int ident() { char *p; char *str; size_t len; for (p = yytext; *p && isspace(*p); p++) ; len = strlen(p); str = grecs_malloc(len + 1); strcpy(str, p); yylval.ident.locus = grecs_current_locus; yylval.ident.string = str; return IDENT; } -void -grecs_lex_trace(int n) -{ - yy_flex_debug = -n; -} - grecs_value_t * grecs_value_ptr_from_static(grecs_value_t *input) { grecs_value_t *ptr = grecs_malloc(sizeof(*ptr)); *ptr = *input; return ptr; } static int assign_locus(grecs_locus_t *ploc, char *name, char *line, size_t *pxlines) { diff --git a/src/grecs.h b/src/grecs.h index 61a915b..ff47698 100644 --- a/src/grecs.h +++ b/src/grecs.h @@ -189,36 +189,57 @@ void *grecs_realloc(void *ptr, size_t size); void grecs_alloc_die(void); char *grecs_strdup(const char *str); void grecs_free(void *ptr); grecs_value_t *grecs_value_ptr_from_static(grecs_value_t *input); extern void (*grecs_print_diag_fun)(grecs_locus_t *, int, int, const char*); void grecs_warning(grecs_locus_t *locus, int errcode, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 3, 4))); void grecs_error(grecs_locus_t *locus, int errcode, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 3, 4))); + + +extern int grecs_trace_flags; + +#define GRECS_TRACE_GRAM 0x01 +#define GRECS_TRACE_LEX 0x02 void grecs_gram_trace(int n); void grecs_lex_trace(int n); + -int grecs_lex_begin(const char*); +int grecs_lex_begin(const char*, int); void grecs_lex_end(int err); struct grecs_node *grecs_parse(const char *name); + +extern struct grecs_node *(*grecs_parser_fun)(const char *name, int trace); + +/* Parsers: */ +struct grecs_node *grecs_grecs_parser(const char *name, int traceflags); +struct grecs_node *grecs_meta1_parser(const char *name, int traceflags); + struct grecs_list *_grecs_simple_list_create(int dispose); struct grecs_list *grecs_value_list_create(void); +void grecs_line_acc_create(void); +void grecs_line_acc_free(void); +void grecs_line_acc_grow_char(int c); +void grecs_line_acc_grow_char_unescape(int c); +void grecs_line_acc_grow(const char *text, size_t len); +void grecs_line_acc_grow_unescape_last(char *text, size_t len); + void grecs_line_begin(void); -void grecs_line_add(const char *text, size_t len); +#define grecs_line_add grecs_line_acc_grow char *grecs_line_finish(void); extern int grecs_string_convert(void *target, enum grecs_data_type type, const char *string, grecs_locus_t *locus); extern void grecs_process_ident(struct grecs_keyword *kwp, grecs_value_t *value, void *base, grecs_locus_t *locus); struct grecs_node *grecs_node_create(enum grecs_node_type type, grecs_locus_t *loc); void grecs_node_bind(struct grecs_node *master, struct grecs_node *node, @@ -286,24 +307,31 @@ void *grecs_list_pop(struct grecs_list *lp); void *grecs_list_locate(struct grecs_list *lp, void *data); void *grecs_list_index(struct grecs_list *lp, size_t idx); void *grecs_list_remove_tail(struct grecs_list *lp); void grecs_list_remove_entry(struct grecs_list *lp, struct grecs_list_entry *ent); void grecs_list_clear(struct grecs_list *lp); void grecs_list_free(struct grecs_list *lp); void grecs_list_add(struct grecs_list *dst, struct grecs_list *src); int grecs_vasprintf(char **pbuf, size_t *psize, const char *fmt, va_list ap); int grecs_asprintf(char **pbuf, size_t *psize, const char *fmt, ...); +#define GRECS_TXTACC_BUFSIZE 1024 +struct grecs_txtacc *grecs_txtacc_create(void); +void grecs_txtacc_free(struct grecs_txtacc *acc); +void grecs_txtacc_grow(struct grecs_txtacc *acc, const char *buf, size_t size); +char *grecs_txtacc_finish(struct grecs_txtacc *acc, int steal); +void grecs_txtacc_free_string(struct grecs_txtacc *acc, char *str); + struct grecs_symtab; struct grecs_syment { char *name; }; typedef int (*grecs_symtab_enumerator_t)(void *sym, void *data); |