📄 scan.l
字号:
/* National character. * We will pass this along as a normal character string, * but preceded with an internally-generated "NCHAR". */ const ScanKeyword *keyword; /* This had better be a keyword! */ keyword = ScanKeywordLookup("nchar"); Assert(keyword != NULL); yylval.keyword = keyword->name; token_start = yytext; BEGIN(xq); startlit(); return keyword->value; }{xqstart} { token_start = yytext; BEGIN(xq); startlit(); }<xq>{xqstop} { BEGIN(INITIAL); yylval.str = litbufdup(); return SCONST; }<xq>{xqdouble} { addlitchar('\''); }<xq>{xqinside} { addlit(yytext, yyleng); }<xq>{xqescape} { addlitchar(unescape_single_char(yytext[1])); }<xq>{xqoctesc} { unsigned char c = strtoul(yytext+1, NULL, 8); addlitchar(c); }<xq>{xqcat} { /* ignore */ }<xq><<EOF>> { yyerror("unterminated quoted string"); }{xdstart} { token_start = yytext; BEGIN(xd); startlit(); }<xd>{xdstop} { char *ident; BEGIN(INITIAL); if (literallen == 0) yyerror("zero-length delimited identifier"); ident = litbufdup(); if (literallen >= NAMEDATALEN) truncate_identifier(ident, literallen, true); yylval.str = ident; return IDENT; }<xd>{xddouble} { addlitchar('"'); }<xd>{xdinside} { addlit(yytext, yyleng); }<xd><<EOF>> { yyerror("unterminated quoted identifier"); }{typecast} { return TYPECAST; }{self} { return yytext[0]; }{operator} { /* * Check for embedded slash-star or dash-dash; those * are comment starts, so operator must stop there. * Note that slash-star or dash-dash at the first * character will match a prior rule, not this one. */ int nchars = yyleng; char *slashstar = strstr(yytext, "/*"); char *dashdash = strstr(yytext, "--"); if (slashstar && dashdash) { /* if both appear, take the first one */ if (slashstar > dashdash) slashstar = dashdash; } else if (!slashstar) slashstar = dashdash; if (slashstar) nchars = slashstar - yytext; /* * For SQL compatibility, '+' and '-' cannot be the * last char of a multi-char operator unless the operator * contains chars that are not in SQL operators. * The idea is to lex '=-' as two operators, but not * to forbid operator names like '?-' that could not be * sequences of SQL operators. */ while (nchars > 1 && (yytext[nchars-1] == '+' || yytext[nchars-1] == '-')) { int ic; for (ic = nchars-2; ic >= 0; ic--) { if (strchr("~!@#^&|`?%", yytext[ic])) break; } if (ic >= 0) break; /* found a char that makes it OK */ nchars--; /* else remove the +/-, and check again */ } if (nchars < yyleng) { /* Strip the unwanted chars from the token */ yyless(nchars); /* * If what we have left is only one char, and it's * one of the characters matching "self", then * return it as a character token the same way * that the "self" rule would have. */ if (nchars == 1 && strchr(",()[].;:+-*/%^<>=", yytext[0])) return yytext[0]; } /* Convert "!=" operator to "<>" for compatibility */ if (strcmp(yytext, "!=") == 0) yylval.str = pstrdup("<>"); else yylval.str = pstrdup(yytext); return Op; }{param} { yylval.ival = atol(yytext + 1); return PARAM; }{integer} { long val; char* endptr; errno = 0; val = strtol(yytext, &endptr, 10); if (*endptr != '\0' || errno == ERANGE#ifdef HAVE_LONG_INT_64 /* if long > 32 bits, check for overflow of int4 */ || val != (long) ((int32) val)#endif ) { /* integer too large, treat it as a float */ yylval.str = pstrdup(yytext); return FCONST; } yylval.ival = val; return ICONST; }{decimal} { yylval.str = pstrdup(yytext); return FCONST; }{real} { yylval.str = pstrdup(yytext); return FCONST; }{identifier} { const ScanKeyword *keyword; char *ident; /* Is it a keyword? */ keyword = ScanKeywordLookup(yytext); if (keyword != NULL) { yylval.keyword = keyword->name; return keyword->value; } /* * No. Convert the identifier to lower case, and truncate * if necessary. */ ident = downcase_truncate_identifier(yytext, yyleng, true); yylval.str = ident; return IDENT; }{other} { return yytext[0]; }%%voidyyerror(const char *message){ const char *loc = token_start ? token_start : yytext; int cursorpos; /* in multibyte encodings, return index in characters not bytes */ cursorpos = pg_mbstrlen_with_len(scanbuf, loc - scanbuf) + 1; if (*loc == YY_END_OF_BUFFER_CHAR) { ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), /* translator: %s is typically "syntax error" */ errmsg("%s at end of input", message), errposition(cursorpos))); } else { ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), /* translator: first %s is typically "syntax error" */ errmsg("%s at or near \"%s\"", message, loc), errposition(cursorpos))); }}/* * Called before any actual parsing is done */voidscanner_init(const char *str){ Size slen = strlen(str); /* * Might be left over after ereport() */ if (YY_CURRENT_BUFFER) yy_delete_buffer(YY_CURRENT_BUFFER); /* * Make a scan buffer with special termination needed by flex. */ scanbuf = palloc(slen + 2); memcpy(scanbuf, str, slen); scanbuf[slen] = scanbuf[slen + 1] = YY_END_OF_BUFFER_CHAR; scanbufhandle = yy_scan_buffer(scanbuf, slen + 2); /* initialize literal buffer to a reasonable but expansible size */ literalalloc = 128; literalbuf = (char *) palloc(literalalloc); startlit(); BEGIN(INITIAL);}/* * Called after parsing is done to clean up after scanner_init() */voidscanner_finish(void){ yy_delete_buffer(scanbufhandle); pfree(scanbuf);}static voidaddlit(char *ytext, int yleng){ /* enlarge buffer if needed */ if ((literallen+yleng) >= literalalloc) { do { literalalloc *= 2; } while ((literallen+yleng) >= literalalloc); literalbuf = (char *) repalloc(literalbuf, literalalloc); } /* append new data, add trailing null */ memcpy(literalbuf+literallen, ytext, yleng); literallen += yleng; literalbuf[literallen] = '\0';}static voidaddlitchar(unsigned char ychar){ /* enlarge buffer if needed */ if ((literallen+1) >= literalalloc) { literalalloc *= 2; literalbuf = (char *) repalloc(literalbuf, literalalloc); } /* append new data, add trailing null */ literalbuf[literallen] = ychar; literallen += 1; literalbuf[literallen] = '\0';}/* * One might be tempted to write pstrdup(literalbuf) instead of this, * but for long literals this is much faster because the length is * already known. */static char *litbufdup(void){ char *new; new = palloc(literallen + 1); memcpy(new, literalbuf, literallen+1); return new;}unsigned charunescape_single_char(unsigned char c){ switch (c) { case 'b': return '\b'; case 'f': return '\f'; case 'n': return '\n'; case 'r': return '\r'; case 't': return '\t'; default: return c; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -