summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--buf.c39
-rw-r--r--configure.in1
-rw-r--r--doc/flex.texi23
-rw-r--r--flexdef.h17
-rw-r--r--main.c10
-rw-r--r--scan.l43
-rw-r--r--tests/Makefile.am2
-rw-r--r--tests/descriptions1
-rw-r--r--tests/test-top/.cvsignore6
-rw-r--r--tests/test-top/Makefile.am54
-rw-r--r--tests/test-top/main.c63
-rw-r--r--tests/test-top/scanner.l53
-rw-r--r--tests/test-top/test.input3
13 files changed, 298 insertions, 17 deletions
diff --git a/buf.c b/buf.c
index 833837e..647be69 100644
--- a/buf.c
+++ b/buf.c
@@ -33,11 +33,24 @@
#include "flexdef.h"
+/* Take note: The buffer object is sometimes used as a String buffer (one
+ * continuous string), and sometimes used as a list of strings, usually line by
+ * line.
+ *
+ * The type is specified in buf_init by the elt_size. If the elt_size is
+ * sizeof(char), then the buffer should be treated as string buffer. If the
+ * elt_size is sizeof(char*), then the buffer should be treated as a list of
+ * strings.
+ *
+ * Certain functions are only appropriate for one type or the other.
+ */
+
/* global buffers. */
-struct Buf userdef_buf; /* for user #definitions triggered by cmd-line. */
-struct Buf defs_buf; /* for #define's autogenerated. List of strings. */
-struct Buf yydmap_buf; /* string buffer to hold yydmap elements */
-struct Buf m4defs_buf; /**< Holds m4 definitions. List of strings. */
+struct Buf userdef_buf; /**< for user #definitions triggered by cmd-line. */
+struct Buf defs_buf; /**< for #define's autogenerated. List of strings. */
+struct Buf yydmap_buf; /**< string buffer to hold yydmap elements */
+struct Buf m4defs_buf; /**< m4 definitions. List of strings. */
+struct Buf top_buf; /**< contains %top code. String buffer. */
struct Buf *buf_print_strings(struct Buf * buf, FILE* out)
{
@@ -66,6 +79,24 @@ struct Buf *buf_prints (struct Buf *buf, const char *fmt, const char *s)
return buf;
}
+/** Append a line directive to the string buffer.
+ * @param buf A string buffer.
+ * @param filename file name
+ * @param lineno line number
+ * @return buf
+ */
+struct Buf *buf_linedir (struct Buf *buf, const char* filename, int lineno)
+{
+ char *t, *fmt = "#line %d \"%s\"\n";
+
+ t = flex_alloc (strlen (fmt) + strlen (filename) + (int)(1 + log(lineno>=0?lineno:-lineno)/log(10)) + 1);
+ sprintf (t, fmt, lineno, filename);
+ buf = buf_strappend (buf, t);
+ flex_free (t);
+ return buf;
+}
+
+
/** Append the contents of @a src to @a dest.
* @param @a dest the destination buffer
* @param @a dest the source buffer
diff --git a/configure.in b/configure.in
index 63ce572..768ede9 100644
--- a/configure.in
+++ b/configure.in
@@ -126,6 +126,7 @@ tests/test-c++-basic/Makefile
tests/test-bison-nr/Makefile
tests/test-reject/Makefile
tests/test-c++-multiple-scanners/Makefile
+tests/test-top/Makefile
dnl --new-test-here-- This line is processed by tests/create-test.
)
diff --git a/doc/flex.texi b/doc/flex.texi
index f299338..64d9767 100644
--- a/doc/flex.texi
+++ b/doc/flex.texi
@@ -531,6 +531,29 @@ is also copied verbatim to the output (with the %@{ and %@} symbols
removed). The %@{ and %@} symbols must appear unindented on lines by
themselves.
+@cindex %top
+
+A @code{%top} block is similar to a @samp{%@{} ... @samp{%@}} block, except
+that the code in a @code{%top} block is relocated to the @emph{top} of the
+generated file, before any flex definitions @footnote{Actually,
+@code{yyIN_HEADER} is defined before the @samp{%top} block.}.
+The @code{%top} block is useful when you want certain preprocessor macros to be
+defined or certain files to be included before the generated code.
+The single characters, @samp{@{} and @samp{@}} are used to delimit the
+@code{%top} block, as show in the example below:
+
+@example
+@verbatim
+ %top{
+ /* This code goes at the "top" of the generated file. */
+ #include <stdint.h>
+ #include <inttypes.h>
+ }
+@end verbatim
+@end example
+
+Multiple @code{%top} blocks are allowed, and their order is preserved.
+
@node Rules Section, User Code Section, Definitions Section, Format
@section Format of the Rules Section
diff --git a/flexdef.h b/flexdef.h
index d704cf1..facc266 100644
--- a/flexdef.h
+++ b/flexdef.h
@@ -1094,18 +1094,13 @@ extern struct Buf *buf_prints PROTO((struct Buf *buf, const char *fmt, const cha
extern struct Buf *buf_m4_define PROTO((struct Buf *buf, const char* def, const char* val));
extern struct Buf *buf_m4_undefine PROTO((struct Buf *buf, const char* def));
extern struct Buf *buf_print_strings PROTO((struct Buf * buf, FILE* out));
+extern struct Buf *buf_linedir PROTO((struct Buf *buf, const char* filename, int lineno));
-/* a string buffer for #define's generated by user-options on cmd line. */
-extern struct Buf userdef_buf;
-
-/* a char* buffer to save #define'd some symbols generated by flex. */
-extern struct Buf defs_buf;
-
-/* a string buffer to hold yydmap elements */
-extern struct Buf yydmap_buf;
-
-/* Holds m4 definitions. */
-extern struct Buf m4defs_buf;
+extern struct Buf userdef_buf; /* a string buffer for #define's generated by user-options on cmd line. */
+extern struct Buf defs_buf; /* a char* buffer to save #define'd some symbols generated by flex. */
+extern struct Buf yydmap_buf; /* a string buffer to hold yydmap elements */
+extern struct Buf m4defs_buf; /* Holds m4 definitions. */
+extern struct Buf top_buf; /* contains %top code. String buffer. */
/* For blocking out code from the header file. */
#define OUT_BEGIN_CODE() outn("m4_ifdef( [[M4_YY_IN_HEADER]],,[[")
diff --git a/main.c b/main.c
index 94a78da..748dfe9 100644
--- a/main.c
+++ b/main.c
@@ -441,9 +441,18 @@ void check_options ()
buf_destroy(&tmpbuf);
}
+ /* This is where we begin writing to the file. */
+
+ /* Dump the %top code. */
+ if( top_buf.elts)
+ outn((char*) top_buf.elts);
+
/* Dump the m4 definitions. */
buf_print_strings(&m4defs_buf, stdout);
m4defs_buf.nelts = 0; /* memory leak here. */
+
+ /* Place a bogus line directive, it will be fixed in the filter. */
+ outn("#line 0 \"M4_YY_OUTFILE_NAME\"\n");
/* Dump the user defined preproc directives. */
if (userdef_buf.elts)
@@ -935,6 +944,7 @@ void flexinit (argc, argv)
buf_init (&userdef_buf, sizeof (char)); /* one long string */
buf_init (&defs_buf, sizeof (char *)); /* list of strings */
buf_init (&yydmap_buf, sizeof (char)); /* one long string */
+ buf_init (&top_buf, sizeof (char)); /* one long string */
{
const char * m4defs_init_str[] = {"m4_changequote\n",
diff --git a/scan.l b/scan.l
index bb694a3..ab48a40 100644
--- a/scan.l
+++ b/scan.l
@@ -95,7 +95,7 @@ extern bool tablesverify, tablesext;
%x SECT2 SECT2PROLOG SECT3 CODEBLOCK PICKUPDEF SC CARETISBOL NUM QUOTE
%x FIRSTCCL CCL ACTION RECOVER COMMENT ACTION_STRING PERCENT_BRACE_ACTION
-%x OPTION LINEDIR
+%x OPTION LINEDIR CODEBLOCK_MATCH_BRACE
WS [[:blank:]]+
OPTWS [[:blank:]]*
@@ -122,7 +122,7 @@ LEXOPT [aceknopr]
static int option_sense;
int doing_codeblock = false;
- int i;
+ int i, brace_depth=0, brace_start_line=0;
Char nmdef[MAXLINE];
@@ -138,6 +138,15 @@ LEXOPT [aceknopr]
indented_code = false;
BEGIN(CODEBLOCK);
}
+ ^"%top"[[:blank:]]*"{"[[:blank:]]*{NL} {
+ brace_start_line = linenum;
+ ++linenum;
+ buf_linedir( &top_buf, infilename?infilename:"<stdin>", linenum);
+ brace_depth = 1;
+ yy_push_state(CODEBLOCK_MATCH_BRACE);
+ }
+
+ ^"%top".* synerr( _("malformed '%top' directive") );
{WS} /* discard */
@@ -214,6 +223,36 @@ LEXOPT [aceknopr]
}
}
+<CODEBLOCK_MATCH_BRACE>{
+ "}" {
+ if( --brace_depth == 0){
+ /* TODO: Matched. */
+ yy_pop_state();
+ }else
+ buf_strnappend(&top_buf, yytext, yyleng);
+ }
+
+ "{" {
+ brace_depth++;
+ buf_strnappend(&top_buf, yytext, yyleng);
+ }
+
+ {NL} {
+ ++linenum;
+ buf_strnappend(&top_buf, yytext, yyleng);
+ }
+
+ [^{}\r\n]+ {
+ buf_strnappend(&top_buf, yytext, yyleng);
+ }
+
+ <<EOF>> {
+ linenum = brace_start_line;
+ synerr(_("Unmatched '{'"));
+ yyterminate();
+ }
+}
+
<PICKUPDEF>{
{WS} /* separates name and definition */
diff --git a/tests/Makefile.am b/tests/Makefile.am
index b5c96c3..f3b78ef 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -48,6 +48,7 @@ DIST_SUBDIRS = \
test-lineno-nr \
test-linedir-r \
TEMPLATE \
+ test-top \
test-array-nr \
test-array-r \
test-c-cpp-nr \
@@ -102,6 +103,7 @@ SUBDIRS = \
test-yyextra \
test-noansi-nr \
test-noansi-r \
+ test-top \
test-table-opts
# clean up before running the test suite so we dont test old builds of test code
diff --git a/tests/descriptions b/tests/descriptions
index 4b45b74..6dc76c4 100644
--- a/tests/descriptions
+++ b/tests/descriptions
@@ -37,4 +37,5 @@ reject - Check REJECT code.
string-nr - Scan strings, non-reentrant.
string-r - Scan strings, reentrant.
table-opts - Try every table compression option.
+top - Test %top directive.
yyextra - Test yyextra.
diff --git a/tests/test-top/.cvsignore b/tests/test-top/.cvsignore
new file mode 100644
index 0000000..b095dd2
--- /dev/null
+++ b/tests/test-top/.cvsignore
@@ -0,0 +1,6 @@
+Makefile
+Makefile.in
+scanner.c
+scanner.h
+test-top
+OUTPUT
diff --git a/tests/test-top/Makefile.am b/tests/test-top/Makefile.am
new file mode 100644
index 0000000..51e6d6b
--- /dev/null
+++ b/tests/test-top/Makefile.am
@@ -0,0 +1,54 @@
+# This file is part of flex.
+
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+
+# Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+
+# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE.
+
+
+FLEX = $(top_builddir)/flex
+
+builddir = @builddir@
+
+EXTRA_DIST = scanner.l test.input main.c
+CLEANFILES = scanner.c scanner.h test-top OUTPUT $(OBJS)
+OBJS = scanner.o main.o
+
+AM_CPPFLAGS = -I$(srcdir) -I$(top_srcdir) -I$(top_builddir) -I$(builddir)
+#LDFLAGS = $(top_srcdir)/libfl.a
+LFLAGS = --header="scanner.h"
+#YFLAGS = --defines --output=parser.c
+
+testname = test-top
+
+scanner.c: $(srcdir)/scanner.l
+ $(FLEX) $(LFLAGS) $<
+
+parser.c: $(srcdir)/parser.y
+ $(BISON) $(YFLAGS) $<
+
+$(testname)$(EXEEXT): $(OBJS)
+ $(CC) -o $@ $(LDFLAGS) $(OBJS) $(LOADLIBES)
+
+test: $(testname)$(EXEEXT)
+ ./$(testname)$(EXEEXT) < $(srcdir)/test.input
+
+.c.o:
+ $(CC) -c -o $@ $(AM_CPPFLAGS) $(CPPFLAGS) $(CFLAGS) $<
+
+scanner.h: scanner.c
+main.o: scanner.h
diff --git a/tests/test-top/main.c b/tests/test-top/main.c
new file mode 100644
index 0000000..353a63e
--- /dev/null
+++ b/tests/test-top/main.c
@@ -0,0 +1,63 @@
+/*
+ * This file is part of flex.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+#include "scanner.h"
+
+/* The scanner itself is not important here.
+ * We simply try to use all the functions that are exported in the
+ * header, to see if we get any compiler warnings.
+ */
+int
+main ( int argc, char** argv )
+{
+ yyscan_t scanner;
+ FILE *fp;
+ char * extra = "EXTRA";
+
+ testlex_init(&scanner);
+ testset_in(stdin,scanner);
+ testset_out(stdout,scanner);
+ testset_extra(extra,scanner);
+
+ fp = testget_in(scanner);
+ fp = testget_out(scanner);
+
+ while(testlex(scanner)) {
+ char * text;
+ int line;
+ line = testget_lineno(scanner);
+ text = testget_text(scanner);
+
+ if( (char*)testget_extra(scanner) != extra)
+ break;
+
+ if ( !text || line < 0)
+ continue;
+ }
+ testlex_destroy(scanner);
+ printf("TEST RETURNING OK.\n");
+ return 0;
+}
+
+
+/* vim:set tabstop=8 softtabstop=4 shiftwidth=4: */
diff --git a/tests/test-top/scanner.l b/tests/test-top/scanner.l
new file mode 100644
index 0000000..be329b0
--- /dev/null
+++ b/tests/test-top/scanner.l
@@ -0,0 +1,53 @@
+/*
+ * This file is part of flex.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE.
+ */
+
+%{
+/* Build "scanner.c".
+ The scanner is not important.
+ This test is really about compilation. See "main.c".
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include "config.h"
+
+#ifndef DEFINE_ME
+#error "DEFINE_ME undefined!"
+#endif
+%}
+
+%top{
+#define DEFINE_ME 1
+}
+
+%option reentrant
+%option 8bit outfile="scanner.c" prefix="test"
+%option nounput nomain noyywrap
+%option warn
+
+
+%%
+
+.|\n { }
+
+%%
+
diff --git a/tests/test-top/test.input b/tests/test-top/test.input
new file mode 100644
index 0000000..2ce5001
--- /dev/null
+++ b/tests/test-top/test.input
@@ -0,0 +1,3 @@
+Any input is ok for this scanner.
+We only care if it links.
+