aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuy Harris <guy@alum.mit.edu>2015-12-04 19:00:46 -0800
committerGuy Harris <guy@alum.mit.edu>2015-12-04 19:00:46 -0800
commit5823e2382c11cb9cdbe895c7e34b045a25c3bd78 (patch)
treeb05d73b2755a22d00fca2e46dcec80c08b3fff6f
parent720b9a33921bbc017ef39bd57dc25a8e9ce9535c (diff)
downloadlibpcap-5823e2382c11cb9cdbe895c7e34b045a25c3bd78.tar.gz
Generate a reentrant lexical analyzer and parser.
This doesn't make pcap_compile() completely reentrant and thread-safe, but it's a significant step along the way. Get rid of some stuff left over from when we supported classic Lex.
-rw-r--r--gencode.c29
-rw-r--r--gencode.h4
-rw-r--r--grammar.y18
-rw-r--r--pcap-int.h2
-rw-r--r--scanner.l129
5 files changed, 98 insertions, 84 deletions
diff --git a/gencode.c b/gencode.c
index 165920e6..1d4d8947 100644
--- a/gencode.c
+++ b/gencode.c
@@ -74,6 +74,9 @@
#include "pcap/ipnet.h"
#include "arcnet.h"
+#include "grammar.h"
+#include "scanner.h"
+
#if defined(linux) && defined(PF_PACKET) && defined(SO_ATTACH_FILTER)
#include <linux/types.h>
#include <linux/if_packet.h>
@@ -472,6 +475,8 @@ pcap_compile(pcap_t *p, struct bpf_program *program,
{
extern int n_errors;
const char * volatile xbuf = buf;
+ yyscan_t scanner = NULL;
+ YY_BUFFER_STATE in_buffer = NULL;
u_int len;
int rc;
@@ -512,8 +517,6 @@ pcap_compile(pcap_t *p, struct bpf_program *program,
ai = NULL;
}
#endif
- lex_cleanup();
- freechunks();
rc = -1;
goto quit;
}
@@ -528,9 +531,11 @@ pcap_compile(pcap_t *p, struct bpf_program *program,
goto quit;
}
- lex_init(xbuf ? xbuf : "");
+ if (pcap_lex_init(&scanner) != 0)
+ bpf_error("can't initialize scanner: %s", pcap_strerror(errno));
+ in_buffer = pcap__scan_string(xbuf ? xbuf : "", scanner);
init_linktype(p);
- (void)pcap_parse();
+ (void)pcap_parse(scanner);
if (n_errors)
syntax();
@@ -547,13 +552,21 @@ pcap_compile(pcap_t *p, struct bpf_program *program,
program->bf_insns = icode_to_fcode(root, &len);
program->bf_len = len;
- lex_cleanup();
- pcap_lex_destroy();
- freechunks();
-
rc = 0; /* We're all okay */
quit:
+ /*
+ * Clean up everything for the lexical analyzer.
+ */
+ if (in_buffer != NULL)
+ pcap__delete_buffer(in_buffer, scanner);
+ if (scanner != NULL)
+ pcap_lex_destroy(scanner);
+
+ /*
+ * Clean up our own allocated memory.
+ */
+ freechunks();
#ifdef _WIN32
LeaveCriticalSection(&g_PcapCompileCriticalSection);
diff --git a/gencode.h b/gencode.h
index 67ed0dc0..5abca72d 100644
--- a/gencode.h
+++ b/gencode.h
@@ -353,9 +353,7 @@ void finish_parse(struct block *);
char *sdup(const char *);
struct bpf_insn *icode_to_fcode(struct block *, u_int *);
-int pcap_parse(void);
-void lex_init(const char *);
-void lex_cleanup(void);
+int pcap_parse(void *);
void sappend(struct slist *, struct slist *);
/* XXX */
diff --git a/grammar.y b/grammar.y
index cb94824b..5acf13ca 100644
--- a/grammar.y
+++ b/grammar.y
@@ -1,3 +1,16 @@
+/*
+ * We want a reentrant parser.
+ */
+%pure-parser
+
+/*
+ * We also want a reentrant scanner, so we have to pass the
+ * handle for the reentrant scanner to the parser, and the
+ * parser has to pass it to the lexical analyzer.
+ */
+%parse-param {yyscan_t yyscanner}
+%lex-param {yyscan_t yyscanner}
+
%{
/*
* Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996
@@ -49,6 +62,9 @@ struct rtentry;
#include "pcap-int.h"
#include "gencode.h"
+#include "grammar.h"
+#include "scanner.h"
+
#ifdef HAVE_NET_PFVAR_H
#include <net/if.h>
#include <net/pfvar.h>
@@ -174,7 +190,7 @@ int n_errors = 0;
static struct qual qerr = { Q_UNDEF, Q_UNDEF, Q_UNDEF, Q_UNDEF };
static void
-yyerror(const char *msg)
+yyerror(yyscan_t yyscanner, const char *msg)
{
++n_errors;
bpf_error("%s", msg);
diff --git a/pcap-int.h b/pcap-int.h
index 091b0419..04d2ba4b 100644
--- a/pcap-int.h
+++ b/pcap-int.h
@@ -361,8 +361,6 @@ struct oneshot_userdata {
pcap_t *pd;
};
-int yylex(void);
-
#ifndef min
#define min(a, b) ((a) > (b) ? (b) : (a))
#endif
diff --git a/scanner.l b/scanner.l
index 6b46fbe3..451f86b4 100644
--- a/scanner.l
+++ b/scanner.l
@@ -6,10 +6,27 @@
}
/*
+ * We want a reentrant scanner.
+ */
+%option reentrant
+
+/*
+ * We don't use input, so don't generate code for it.
+ */
+%option noinput
+
+/*
+ * We don't use unput, so don't generate code for it.
+ */
+%option nounput
+
+/*
* We don't read from the terminal.
*/
%option never-interactive
+%option bison-bridge
+
%{
/*
* Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
@@ -53,6 +70,15 @@
#include "gencode.h"
+#include "grammar.h"
+
+/*
+ * Earlier versions of Flex dsn't declare these, so we declare them
+ * ourselves to squelch warnings.
+ */
+int pcap_get_column(yyscan_t);
+void pcap_set_column(int, yyscan_t);
+
#ifdef INET6
#ifdef _WIN32
@@ -101,20 +127,6 @@
static int stoi(char *);
static inline int xdtoi(int);
-#ifdef FLEX_SCANNER
-#define YY_NO_INPUT
-#define YY_NO_UNPUT
-static YY_BUFFER_STATE in_buffer;
-#else
-static const char *in_buffer;
-
-#undef getc
-#define getc(fp) (*in_buffer == 0 ? EOF : *in_buffer++)
-#endif
-
-#define yylval pcap_lval
-extern YYSTYPE yylval;
-
%}
N ([0-9]+|(0X|0x)[0-9A-Fa-f]+)
@@ -357,17 +369,17 @@ hsls return HSLS;
"==" return '=';
"<<" return LSH;
">>" return RSH;
-${B} { yylval.e = pcap_ether_aton(((char *)yytext)+1);
- if (yylval.e == NULL)
+${B} { yylval->e = pcap_ether_aton(((char *)yytext)+1);
+ if (yylval->e == NULL)
bpf_error("malloc");
return AID; }
-{MAC} { yylval.e = pcap_ether_aton((char *)yytext);
- if (yylval.e == NULL)
+{MAC} { yylval->e = pcap_ether_aton((char *)yytext);
+ if (yylval->e == NULL)
bpf_error("malloc");
return EID; }
-{N} { yylval.i = stoi((char *)yytext); return NUM; }
+{N} { yylval->i = stoi((char *)yytext); return NUM; }
({N}\.{N})|({N}\.{N}\.{N})|({N}\.{N}\.{N}\.{N}) {
- yylval.s = sdup((char *)yytext); return HID; }
+ yylval->s = sdup((char *)yytext); return HID; }
{V6} {
#ifdef INET6
struct addrinfo hints, *res;
@@ -378,67 +390,44 @@ ${B} { yylval.e = pcap_ether_aton(((char *)yytext)+1);
bpf_error("bogus IPv6 address %s", yytext);
else {
freeaddrinfo(res);
- yylval.s = sdup((char *)yytext); return HID6;
+ yylval->s = sdup((char *)yytext); return HID6;
}
#else
bpf_error("IPv6 address %s not supported", yytext);
#endif /*INET6*/
}
{B}:+({B}:+)+ { bpf_error("bogus ethernet address %s", yytext); }
-icmptype { yylval.i = 0; return NUM; }
-icmpcode { yylval.i = 1; return NUM; }
-icmp-echoreply { yylval.i = 0; return NUM; }
-icmp-unreach { yylval.i = 3; return NUM; }
-icmp-sourcequench { yylval.i = 4; return NUM; }
-icmp-redirect { yylval.i = 5; return NUM; }
-icmp-echo { yylval.i = 8; return NUM; }
-icmp-routeradvert { yylval.i = 9; return NUM; }
-icmp-routersolicit { yylval.i = 10; return NUM; }
-icmp-timxceed { yylval.i = 11; return NUM; }
-icmp-paramprob { yylval.i = 12; return NUM; }
-icmp-tstamp { yylval.i = 13; return NUM; }
-icmp-tstampreply { yylval.i = 14; return NUM; }
-icmp-ireq { yylval.i = 15; return NUM; }
-icmp-ireqreply { yylval.i = 16; return NUM; }
-icmp-maskreq { yylval.i = 17; return NUM; }
-icmp-maskreply { yylval.i = 18; return NUM; }
-tcpflags { yylval.i = 13; return NUM; }
-tcp-fin { yylval.i = 0x01; return NUM; }
-tcp-syn { yylval.i = 0x02; return NUM; }
-tcp-rst { yylval.i = 0x04; return NUM; }
-tcp-push { yylval.i = 0x08; return NUM; }
-tcp-ack { yylval.i = 0x10; return NUM; }
-tcp-urg { yylval.i = 0x20; return NUM; }
+icmptype { yylval->i = 0; return NUM; }
+icmpcode { yylval->i = 1; return NUM; }
+icmp-echoreply { yylval->i = 0; return NUM; }
+icmp-unreach { yylval->i = 3; return NUM; }
+icmp-sourcequench { yylval->i = 4; return NUM; }
+icmp-redirect { yylval->i = 5; return NUM; }
+icmp-echo { yylval->i = 8; return NUM; }
+icmp-routeradvert { yylval->i = 9; return NUM; }
+icmp-routersolicit { yylval->i = 10; return NUM; }
+icmp-timxceed { yylval->i = 11; return NUM; }
+icmp-paramprob { yylval->i = 12; return NUM; }
+icmp-tstamp { yylval->i = 13; return NUM; }
+icmp-tstampreply { yylval->i = 14; return NUM; }
+icmp-ireq { yylval->i = 15; return NUM; }
+icmp-ireqreply { yylval->i = 16; return NUM; }
+icmp-maskreq { yylval->i = 17; return NUM; }
+icmp-maskreply { yylval->i = 18; return NUM; }
+tcpflags { yylval->i = 13; return NUM; }
+tcp-fin { yylval->i = 0x01; return NUM; }
+tcp-syn { yylval->i = 0x02; return NUM; }
+tcp-rst { yylval->i = 0x04; return NUM; }
+tcp-push { yylval->i = 0x08; return NUM; }
+tcp-ack { yylval->i = 0x10; return NUM; }
+tcp-urg { yylval->i = 0x20; return NUM; }
[A-Za-z0-9]([-_.A-Za-z0-9]*[.A-Za-z0-9])? {
- yylval.s = sdup((char *)yytext); return ID; }
-"\\"[^ !()\n\t]+ { yylval.s = sdup((char *)yytext + 1); return ID; }
+ yylval->s = sdup((char *)yytext); return ID; }
+"\\"[^ !()\n\t]+ { yylval->s = sdup((char *)yytext + 1); return ID; }
[^ \[\]\t\n\-_.A-Za-z0-9!<>()&|=]+ {
bpf_error("illegal token: %s", yytext); }
. { bpf_error("illegal char '%c'", *yytext); }
%%
-void
-lex_init(buf)
- const char *buf;
-{
-#ifdef FLEX_SCANNER
- in_buffer = yy_scan_string(buf);
-#else
- in_buffer = buf;
-#endif
-}
-
-/*
- * Do any cleanup necessary after parsing.
- */
-void
-lex_cleanup()
-{
-#ifdef FLEX_SCANNER
- if (in_buffer != NULL)
- yy_delete_buffer(in_buffer);
- in_buffer = NULL;
-#endif
-}
/*
* Also define a yywrap. Note that if we're using flex, it will