#include "plpgsql.h"
#include "mb/pg_wchar.h"
#include "parser/scanner.h"
#include "pl_gram.h"
Go to the source code of this file.
Data Structures | |
struct | TokenAuxData |
Defines | |
#define | PG_KEYWORD(a, b, c) {a,b,c}, |
#define | MAX_PUSHBACKS 4 |
Functions | |
static int | internal_yylex (TokenAuxData *auxdata) |
static void | push_back_token (int token, TokenAuxData *auxdata) |
static void | location_lineno_init (void) |
int | plpgsql_yylex (void) |
void | plpgsql_push_back_token (int token) |
bool | plpgsql_token_is_unreserved_keyword (int token) |
void | plpgsql_append_source_text (StringInfo buf, int startlocation, int endlocation) |
int | plpgsql_peek (void) |
void | plpgsql_peek2 (int *tok1_p, int *tok2_p, int *tok1_loc, int *tok2_loc) |
int | plpgsql_scanner_errposition (int location) |
void | __attribute__ ((noreturn)) |
int | plpgsql_location_to_lineno (int location) |
int | plpgsql_latest_lineno (void) |
void | plpgsql_scanner_init (const char *str) |
void | plpgsql_scanner_finish (void) |
Variables | |
IdentifierLookup | plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL |
static const ScanKeyword | reserved_keywords [] |
static const int | num_reserved_keywords = lengthof(reserved_keywords) |
static const ScanKeyword | unreserved_keywords [] |
static const int | num_unreserved_keywords = lengthof(unreserved_keywords) |
static core_yyscan_t | yyscanner = NULL |
static core_yy_extra_type | core_yy |
static const char * | scanorig |
static int | plpgsql_yyleng |
static int | num_pushbacks |
static int | pushback_token [MAX_PUSHBACKS] |
static TokenAuxData | pushback_auxdata [MAX_PUSHBACKS] |
static const char * | cur_line_start |
static const char * | cur_line_end |
static int | cur_line_num |
#define MAX_PUSHBACKS 4 |
Definition at line 184 of file pl_scanner.c.
Referenced by push_back_token().
Definition at line 23 of file pl_scanner.c.
void __attribute__ | ( | (noreturn) | ) |
Definition at line 531 of file pl_scanner.c.
References _, ereport, errcode(), errmsg(), ERROR, plpgsql_scanner_errposition(), plpgsql_yyleng, core_yy_extra_type::scanbuf, and yytext.
{ char *yytext = core_yy.scanbuf + plpgsql_yylloc; if (*yytext == '\0') { ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), /* translator: %s is typically the translation of "syntax error" */ errmsg("%s at end of input", _(message)), plpgsql_scanner_errposition(plpgsql_yylloc))); } else { /* * If we have done any lookahead then flex will have restored the * character after the end-of-token. Zap it again so that we report * only the single token here. This modifies scanbuf but we no longer * care about that. */ yytext[plpgsql_yyleng] = '\0'; ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), /* translator: first %s is typically the translation of "syntax error" */ errmsg("%s at or near \"%s\"", _(message), yytext), plpgsql_scanner_errposition(plpgsql_yylloc))); } }
static int internal_yylex | ( | TokenAuxData * | auxdata | ) | [static] |
Definition at line 341 of file pl_scanner.c.
References core_yylex(), TokenAuxData::leng, TokenAuxData::lloc, TokenAuxData::lval, num_pushbacks, pstrdup(), pushback_token, core_yy_extra_type::scanbuf, yyscanner, and yytext.
Referenced by plpgsql_peek(), plpgsql_peek2(), and plpgsql_yylex().
{ int token; const char *yytext; if (num_pushbacks > 0) { num_pushbacks--; token = pushback_token[num_pushbacks]; *auxdata = pushback_auxdata[num_pushbacks]; } else { token = core_yylex(&auxdata->lval.core_yystype, &auxdata->lloc, yyscanner); /* remember the length of yytext before it gets changed */ yytext = core_yy.scanbuf + auxdata->lloc; auxdata->leng = strlen(yytext); /* Check for << >> and #, which the core considers operators */ if (token == Op) { if (strcmp(auxdata->lval.str, "<<") == 0) token = LESS_LESS; else if (strcmp(auxdata->lval.str, ">>") == 0) token = GREATER_GREATER; else if (strcmp(auxdata->lval.str, "#") == 0) token = '#'; } /* The core returns PARAM as ival, but we treat it like IDENT */ else if (token == PARAM) { auxdata->lval.str = pstrdup(yytext); } } return token; }
static void location_lineno_init | ( | void | ) | [static] |
Definition at line 595 of file pl_scanner.c.
References cur_line_end, cur_line_num, cur_line_start, and scanorig.
Referenced by plpgsql_location_to_lineno(), and plpgsql_scanner_init().
{ cur_line_start = scanorig; cur_line_num = 1; cur_line_end = strchr(cur_line_start, '\n'); }
void plpgsql_append_source_text | ( | StringInfo | buf, | |
int | startlocation, | |||
int | endlocation | |||
) |
Definition at line 437 of file pl_scanner.c.
References appendBinaryStringInfo(), Assert, and scanorig.
{ Assert(startlocation <= endlocation); appendBinaryStringInfo(buf, scanorig + startlocation, endlocation - startlocation); }
int plpgsql_latest_lineno | ( | void | ) |
Definition at line 605 of file pl_scanner.c.
References cur_line_num.
Referenced by plpgsql_compile_error_callback().
{ return cur_line_num; }
int plpgsql_location_to_lineno | ( | int | location | ) |
Definition at line 571 of file pl_scanner.c.
References cur_line_end, cur_line_num, cur_line_start, location_lineno_init(), NULL, and scanorig.
{ const char *loc; if (location < 0 || scanorig == NULL) return 0; /* garbage in, garbage out */ loc = scanorig + location; /* be correct, but not fast, if input location goes backwards */ if (loc < cur_line_start) location_lineno_init(); while (cur_line_end != NULL && loc > cur_line_end) { cur_line_start = cur_line_end + 1; cur_line_num++; cur_line_end = strchr(cur_line_start, '\n'); } return cur_line_num; }
int plpgsql_peek | ( | void | ) |
Definition at line 453 of file pl_scanner.c.
References internal_yylex(), and push_back_token().
{ int tok1; TokenAuxData aux1; tok1 = internal_yylex(&aux1); push_back_token(tok1, &aux1); return tok1; }
void plpgsql_peek2 | ( | int * | tok1_p, | |
int * | tok2_p, | |||
int * | tok1_loc, | |||
int * | tok2_loc | |||
) |
Definition at line 472 of file pl_scanner.c.
References internal_yylex(), TokenAuxData::lloc, and push_back_token().
{ int tok1, tok2; TokenAuxData aux1, aux2; tok1 = internal_yylex(&aux1); tok2 = internal_yylex(&aux2); *tok1_p = tok1; if (tok1_loc) *tok1_loc = aux1.lloc; *tok2_p = tok2; if (tok2_loc) *tok2_loc = aux2.lloc; push_back_token(tok2, &aux2); push_back_token(tok1, &aux1); }
void plpgsql_push_back_token | ( | int | token | ) |
Definition at line 403 of file pl_scanner.c.
References TokenAuxData::leng, TokenAuxData::lloc, TokenAuxData::lval, plpgsql_yyleng, and push_back_token().
{ TokenAuxData auxdata; auxdata.lval = plpgsql_yylval; auxdata.lloc = plpgsql_yylloc; auxdata.leng = plpgsql_yyleng; push_back_token(token, &auxdata); }
int plpgsql_scanner_errposition | ( | int | location | ) |
Definition at line 505 of file pl_scanner.c.
References internalerrposition(), internalerrquery(), NULL, pg_mbstrlen_with_len(), and scanorig.
Referenced by __attribute__().
{ int pos; if (location < 0 || scanorig == NULL) return 0; /* no-op if location is unknown */ /* Convert byte offset to character number */ pos = pg_mbstrlen_with_len(scanorig, location) + 1; /* And pass it to the ereport mechanism */ (void) internalerrposition(pos); /* Also pass the function body string */ return internalerrquery(scanorig); }
void plpgsql_scanner_finish | ( | void | ) |
Definition at line 645 of file pl_scanner.c.
References scanner_finish(), scanorig, and yyscanner.
Referenced by do_compile(), and plpgsql_compile_inline().
{ /* release storage */ scanner_finish(yyscanner); /* avoid leaving any dangling pointers */ yyscanner = NULL; scanorig = NULL; }
void plpgsql_scanner_init | ( | const char * | str | ) |
Definition at line 619 of file pl_scanner.c.
References location_lineno_init(), num_pushbacks, num_reserved_keywords, plpgsql_IdentifierLookup, scanner_init(), scanorig, and yyscanner.
Referenced by do_compile(), and plpgsql_compile_inline().
{ /* Start up the core scanner */ yyscanner = scanner_init(str, &core_yy, reserved_keywords, num_reserved_keywords); /* * scanorig points to the original string, which unlike the scanner's * scanbuf won't be modified on-the-fly by flex. Notice that although * yytext points into scanbuf, we rely on being able to apply locations * (offsets from string start) to scanorig as well. */ scanorig = str; /* Other setup */ plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL; num_pushbacks = 0; location_lineno_init(); }
bool plpgsql_token_is_unreserved_keyword | ( | int | token | ) |
Definition at line 420 of file pl_scanner.c.
References i, num_unreserved_keywords, and value.
{ int i; for (i = 0; i < num_unreserved_keywords; i++) { if (unreserved_keywords[i].value == token) return true; } return false; }
int plpgsql_yylex | ( | void | ) |
Definition at line 211 of file pl_scanner.c.
References internal_yylex(), TokenAuxData::leng, TokenAuxData::lloc, TokenAuxData::lval, ScanKeyword::name, num_unreserved_keywords, plpgsql_parse_dblword(), plpgsql_parse_tripword(), plpgsql_parse_word(), plpgsql_yyleng, push_back_token(), core_yy_extra_type::scanbuf, ScanKeywordLookup(), and ScanKeyword::value.
{ int tok1; TokenAuxData aux1; const ScanKeyword *kw; tok1 = internal_yylex(&aux1); if (tok1 == IDENT || tok1 == PARAM) { int tok2; TokenAuxData aux2; tok2 = internal_yylex(&aux2); if (tok2 == '.') { int tok3; TokenAuxData aux3; tok3 = internal_yylex(&aux3); if (tok3 == IDENT) { int tok4; TokenAuxData aux4; tok4 = internal_yylex(&aux4); if (tok4 == '.') { int tok5; TokenAuxData aux5; tok5 = internal_yylex(&aux5); if (tok5 == IDENT) { if (plpgsql_parse_tripword(aux1.lval.str, aux3.lval.str, aux5.lval.str, &aux1.lval.wdatum, &aux1.lval.cword)) tok1 = T_DATUM; else tok1 = T_CWORD; } else { /* not A.B.C, so just process A.B */ push_back_token(tok5, &aux5); push_back_token(tok4, &aux4); if (plpgsql_parse_dblword(aux1.lval.str, aux3.lval.str, &aux1.lval.wdatum, &aux1.lval.cword)) tok1 = T_DATUM; else tok1 = T_CWORD; } } else { /* not A.B.C, so just process A.B */ push_back_token(tok4, &aux4); if (plpgsql_parse_dblword(aux1.lval.str, aux3.lval.str, &aux1.lval.wdatum, &aux1.lval.cword)) tok1 = T_DATUM; else tok1 = T_CWORD; } } else { /* not A.B, so just process A */ push_back_token(tok3, &aux3); push_back_token(tok2, &aux2); if (plpgsql_parse_word(aux1.lval.str, core_yy.scanbuf + aux1.lloc, &aux1.lval.wdatum, &aux1.lval.word)) tok1 = T_DATUM; else if (!aux1.lval.word.quoted && (kw = ScanKeywordLookup(aux1.lval.word.ident, unreserved_keywords, num_unreserved_keywords))) { aux1.lval.keyword = kw->name; tok1 = kw->value; } else tok1 = T_WORD; } } else { /* not A.B, so just process A */ push_back_token(tok2, &aux2); if (plpgsql_parse_word(aux1.lval.str, core_yy.scanbuf + aux1.lloc, &aux1.lval.wdatum, &aux1.lval.word)) tok1 = T_DATUM; else if (!aux1.lval.word.quoted && (kw = ScanKeywordLookup(aux1.lval.word.ident, unreserved_keywords, num_unreserved_keywords))) { aux1.lval.keyword = kw->name; tok1 = kw->value; } else tok1 = T_WORD; } } else { /* Not a potential plpgsql variable name, just return the data */ } plpgsql_yylval = aux1.lval; plpgsql_yylloc = aux1.lloc; plpgsql_yyleng = aux1.leng; return tok1; }
static void push_back_token | ( | int | token, | |
TokenAuxData * | auxdata | |||
) | [static] |
Definition at line 387 of file pl_scanner.c.
References elog, ERROR, MAX_PUSHBACKS, num_pushbacks, and pushback_token.
Referenced by plpgsql_peek(), plpgsql_peek2(), plpgsql_push_back_token(), and plpgsql_yylex().
{ if (num_pushbacks >= MAX_PUSHBACKS) elog(ERROR, "too many tokens pushed back"); pushback_token[num_pushbacks] = token; pushback_auxdata[num_pushbacks] = *auxdata; num_pushbacks++; }
core_yy_extra_type core_yy [static] |
Definition at line 175 of file pl_scanner.c.
const char* cur_line_end [static] |
Definition at line 192 of file pl_scanner.c.
Referenced by location_lineno_init(), and plpgsql_location_to_lineno().
int cur_line_num [static] |
Definition at line 193 of file pl_scanner.c.
Referenced by location_lineno_init(), plpgsql_latest_lineno(), and plpgsql_location_to_lineno().
const char* cur_line_start [static] |
Definition at line 191 of file pl_scanner.c.
Referenced by location_lineno_init(), and plpgsql_location_to_lineno().
int num_pushbacks [static] |
Definition at line 186 of file pl_scanner.c.
Referenced by internal_yylex(), plpgsql_scanner_init(), and push_back_token().
const int num_reserved_keywords = lengthof(reserved_keywords) [static] |
Definition at line 105 of file pl_scanner.c.
Referenced by plpgsql_scanner_init().
const int num_unreserved_keywords = lengthof(unreserved_keywords) [static] |
Definition at line 155 of file pl_scanner.c.
Referenced by plpgsql_token_is_unreserved_keyword(), and plpgsql_yylex().
IdentifierLookup plpgsql_IdentifierLookup = IDENTIFIER_LOOKUP_NORMAL |
Definition at line 27 of file pl_scanner.c.
Referenced by plpgsql_parse_dblword(), plpgsql_parse_tripword(), plpgsql_parse_word(), and plpgsql_scanner_init().
int plpgsql_yyleng [static] |
Definition at line 181 of file pl_scanner.c.
Referenced by __attribute__(), plpgsql_push_back_token(), and plpgsql_yylex().
TokenAuxData pushback_auxdata[MAX_PUSHBACKS] [static] |
Definition at line 188 of file pl_scanner.c.
int pushback_token[MAX_PUSHBACKS] [static] |
Definition at line 187 of file pl_scanner.c.
Referenced by internal_yylex(), and push_back_token().
const ScanKeyword reserved_keywords[] [static] |
Definition at line 61 of file pl_scanner.c.
const char* scanorig [static] |
Definition at line 178 of file pl_scanner.c.
Referenced by location_lineno_init(), plpgsql_append_source_text(), plpgsql_location_to_lineno(), plpgsql_scanner_errposition(), plpgsql_scanner_finish(), and plpgsql_scanner_init().
const ScanKeyword unreserved_keywords[] [static] |
Definition at line 107 of file pl_scanner.c.
core_yyscan_t yyscanner = NULL [static] |
Definition at line 174 of file pl_scanner.c.
Referenced by fill_in_constant_lengths(), internal_yylex(), plpgsql_scanner_finish(), plpgsql_scanner_init(), and raw_parser().