1 %{ 2 /*------------------------------------------------------------------------- 3 * 4 * specscanner.l 5 * a lexical scanner for an isolation test specification 6 * 7 * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group 8 * Portions Copyright (c) 1994, Regents of the University of California 9 * 10 *------------------------------------------------------------------------- 11 */ 12 13 static int yyline = 1; /* line number for error reporting */ 14 15 #define LITBUF_INIT 1024 /* initial size of litbuf */ 16 static char *litbuf = NULL; 17 static size_t litbufsize = 0; 18 static size_t litbufpos = 0; 19 20 static void addlitchar(char c); 21 22 /* LCOV_EXCL_START */ 23 24 %} 25 26 %option 8bit 27 %option never-interactive 28 %option nodefault 29 %option noinput 30 %option nounput 31 %option noyywrap 32 %option warn 33 %option prefix="spec_yy" 34 35 36 %x sql 37 %x qident 38 39 non_newline [^\n\r] 40 space [ \t\r\f] 41 42 comment ("#"{non_newline}*) 43 44 digit [0-9] 45 ident_start [A-Za-z\200-\377_] 46 ident_cont [A-Za-z\200-\377_0-9\$] 47 48 identifier {ident_start}{ident_cont}* 49 50 self [,()*] 51 52 %% 53 54 %{ 55 /* Allocate litbuf in first call of yylex() */ 56 if (litbuf == NULL) 57 { 58 litbuf = pg_malloc(LITBUF_INIT); 59 litbufsize = LITBUF_INIT; 60 } 61 %} 62 63 /* Keywords (must appear before the {identifier} rule!) */ 64 notices { return NOTICES; } 65 permutation { return PERMUTATION; } 66 session { return SESSION; } 67 setup { return SETUP; } 68 step { return STEP; } 69 teardown { return TEARDOWN; } 70 71 /* Whitespace and comments */ 72 [\n] { yyline++; } 73 {comment} { /* ignore */ } 74 {space} { /* ignore */ } 75 76 /* Plain identifiers */ 77 {identifier} { 78 yylval.str = pg_strdup(yytext); 79 return(identifier); 80 } 81 82 /* Quoted identifiers: "foo" */ 83 \" { 84 litbufpos = 0; 85 BEGIN(qident); 86 } 87 <qident>\"\" { addlitchar(yytext[0]); } 88 <qident>\" { 89 litbuf[litbufpos] = '\0'; 90 yylval.str = pg_strdup(litbuf); 91 BEGIN(INITIAL); 92 return(identifier); 93 } 94 <qident>. { addlitchar(yytext[0]); } 95 <qident>\n { yyerror("unexpected newline in quoted identifier"); } 96 <qident><<EOF>> { yyerror("unterminated quoted identifier"); } 97 98 /* SQL blocks: { UPDATE ... } */ 99 /* We trim leading/trailing whitespace, otherwise they're unprocessed */ 100 "{"{space}* { 101 102 litbufpos = 0; 103 BEGIN(sql); 104 } 105 <sql>{space}*"}" { 106 litbuf[litbufpos] = '\0'; 107 yylval.str = pg_strdup(litbuf); 108 BEGIN(INITIAL); 109 return(sqlblock); 110 } 111 <sql>. { 112 addlitchar(yytext[0]); 113 } 114 <sql>\n { 115 yyline++; 116 addlitchar(yytext[0]); 117 } 118 <sql><<EOF>> { 119 yyerror("unterminated sql block"); 120 } 121 122 /* Numbers and punctuation */ 123 {digit}+ { 124 yylval.integer = atoi(yytext); 125 return INTEGER; 126 } 127 128 {self} { return yytext[0]; } 129 130 /* Anything else is an error */ 131 . { 132 fprintf(stderr, "syntax error at line %d: unexpected character \"%s\"\n", yyline, yytext); 133 exit(1); 134 } 135 %% 136 137 /* LCOV_EXCL_STOP */ 138 139 static void 140 addlitchar(char c) 141 { 142 /* We must always leave room to add a trailing \0 */ 143 if (litbufpos >= litbufsize - 1) 144 { 145 /* Double the size of litbuf if it gets full */ 146 litbufsize += litbufsize; 147 litbuf = pg_realloc(litbuf, litbufsize); 148 } 149 litbuf[litbufpos++] = c; 150 } 151 152 void 153 yyerror(const char *message) 154 { 155 fprintf(stderr, "%s at line %d\n", message, yyline); 156 exit(1); 157 } 158