]> granicus.if.org Git - postgresql/blob - src/bin/psql/psqlscan_int.h
Split psql's lexer into two separate .l files for SQL and backslash cases.
[postgresql] / src / bin / psql / psqlscan_int.h
1 /*
2  * psqlscan_int.h
3  *        lexical scanner internal declarations
4  *
5  * This file declares the PsqlScanStateData structure used by psqlscan.l
6  * and shared by other lexers compatible with it, such as psqlscanslash.l.
7  *
8  * One difficult aspect of this code is that we need to work in multibyte
9  * encodings that are not ASCII-safe.  A "safe" encoding is one in which each
10  * byte of a multibyte character has the high bit set (it's >= 0x80).  Since
11  * all our lexing rules treat all high-bit-set characters alike, we don't
12  * really need to care whether such a byte is part of a sequence or not.
13  * In an "unsafe" encoding, we still expect the first byte of a multibyte
14  * sequence to be >= 0x80, but later bytes might not be.  If we scan such
15  * a sequence as-is, the lexing rules could easily be fooled into matching
16  * such bytes to ordinary ASCII characters.  Our solution for this is to
17  * substitute 0xFF for each non-first byte within the data presented to flex.
18  * The flex rules will then pass the FF's through unmolested.  The
19  * psqlscan_emit() subroutine is responsible for looking back to the original
20  * string and replacing FF's with the corresponding original bytes.
21  *
22  * Another interesting thing we do here is scan different parts of the same
23  * input with physically separate flex lexers (ie, lexers written in separate
24  * .l files).  We can get away with this because the only part of the
25  * persistent state of a flex lexer that depends on its parsing rule tables
26  * is the start state number, which is easy enough to manage --- usually,
27  * in fact, we just need to set it to INITIAL when changing lexers.  But to
28  * make that work at all, we must use re-entrant lexers, so that all the
29  * relevant state is in the yyscanner_t attached to the PsqlScanState;
30  * if we were using lexers with separate static state we would soon end up
31  * with dangling buffer pointers in one or the other.  Also note that this
32  * is unlikely to work very nicely if the lexers aren't all built with the
33  * same flex version.
34  *
35  * Copyright (c) 2000-2016, PostgreSQL Global Development Group
36  *
37  * src/bin/psql/psqlscan_int.h
38  */
39 #ifndef PSQLSCAN_INT_H
40 #define PSQLSCAN_INT_H
41
42 #include "psqlscan.h"
43
44 /* This is just to allow this file to be compilable standalone */
45 #ifndef YY_TYPEDEF_YY_BUFFER_STATE
46 #define YY_TYPEDEF_YY_BUFFER_STATE
47 typedef struct yy_buffer_state *YY_BUFFER_STATE;
48 #endif
49
50 /*
51  * We use a stack of flex buffers to handle substitution of psql variables.
52  * Each stacked buffer contains the as-yet-unread text from one psql variable.
53  * When we pop the stack all the way, we resume reading from the outer buffer
54  * identified by scanbufhandle.
55  */
56 typedef struct StackElem
57 {
58         YY_BUFFER_STATE buf;            /* flex input control structure */
59         char       *bufstring;          /* data actually being scanned by flex */
60         char       *origstring;         /* copy of original data, if needed */
61         char       *varname;            /* name of variable providing data, or NULL */
62         struct StackElem *next;
63 } StackElem;
64
65 /*
66  * All working state of the lexer must be stored in PsqlScanStateData
67  * between calls.  This allows us to have multiple open lexer operations,
68  * which is needed for nested include files.  The lexer itself is not
69  * recursive, but it must be re-entrant.
70  */
71 typedef struct PsqlScanStateData
72 {
73         yyscan_t        scanner;                /* Flex's state for this PsqlScanState */
74
75         PQExpBuffer output_buf;         /* current output buffer */
76
77         StackElem  *buffer_stack;       /* stack of variable expansion buffers */
78
79         /*
80          * These variables always refer to the outer buffer, never to any stacked
81          * variable-expansion buffer.
82          */
83         YY_BUFFER_STATE scanbufhandle;
84         char       *scanbuf;            /* start of outer-level input buffer */
85         const char *scanline;           /* current input line at outer level */
86
87         /* safe_encoding, curline, refline are used by emit() to replace FFs */
88         int                     encoding;               /* encoding being used now */
89         bool            safe_encoding;  /* is current encoding "safe"? */
90         bool            std_strings;    /* are string literals standard? */
91         const char *curline;            /* actual flex input string for cur buf */
92         const char *refline;            /* original data for cur buffer */
93
94         /*
95          * All this state lives across successive input lines, until explicitly
96          * reset by psql_scan_reset.  start_state is adopted by yylex() on entry,
97          * and updated with its finishing state on exit.
98          */
99         int                     start_state;    /* yylex's starting/finishing state */
100         int                     paren_depth;    /* depth of nesting in parentheses */
101         int                     xcdepth;                /* depth of nesting in slash-star comments */
102         char       *dolqstart;          /* current $foo$ quote start string */
103
104         /*
105          * Callback functions provided by the program making use of the lexer.
106          */
107         const PsqlScanCallbacks *callbacks;
108 } PsqlScanStateData;
109
110
111 /*
112  * Functions exported by psqlscan.l, but only meant for use within
113  * compatible lexers.
114  */
115 extern void psqlscan_push_new_buffer(PsqlScanState state,
116                                                  const char *newstr, const char *varname);
117 extern void psqlscan_pop_buffer_stack(PsqlScanState state);
118 extern void psqlscan_select_top_buffer(PsqlScanState state);
119 extern YY_BUFFER_STATE psqlscan_prepare_buffer(PsqlScanState state,
120                                                 const char *txt, int len,
121                                                 char **txtcopy);
122 extern void psqlscan_emit(PsqlScanState state, const char *txt, int len);
123 extern char *psqlscan_extract_substring(PsqlScanState state,
124                                                    const char *txt, int len);
125 extern void psqlscan_escape_variable(PsqlScanState state,
126                                                  const char *txt, int len,
127                                                  bool as_ident);
128
129 #endif   /* PSQLSCAN_INT_H */