Current section
Files
Jump to
Current section
Files
libgraphqlparser/lexer.lpp
/**
* Copyright (c) 2015, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
%{
#include <cassert>
#include <cctype>
#include <cstdio>
#include <vector>
#include "location.hh"
#include "position.hh"
#include "parser.tab.hpp"
#include "syntaxdefs.h"
// Keep track of token lengths.
#define YY_USER_ACTION yyextra->loc.columns(yyleng);
static void escape(char c, char *buf);
%}
%option bison-bridge bison-locations
%option noyywrap batch noinput nounput
%option reentrant
%option extra-type="struct LexerExtra *"
%x STRING_STATE
%x C_COMMENT_STATE
%x LINE_COMMENT_STATE
FLOAT -?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][+-]?[0-9]+)?
INTEGER -?(0|[1-9][0-9]*)
IDENTIFIER [_A-Za-z][_0-9A-Za-z]*
VARIABLE $[_0-9A-Za-z]+
BOM \xef\xbb\xbf
CRLF \r\n
BADCHAR [\x00-\x08\x0b\x0c\x0e-\x1f]
STRINGCHAR [^\x00-\x1f\\\x22]
blank [ \t,]
newline [\n\r]
notnewline [^\n\r]
%%
%{
yyextra->loc.step();
%}
<STRING_STATE>{
\" {
BEGIN(INITIAL);
yylval->str = yyextra->str.c_str();
return yy::GraphQLParserImpl::token::TOK_STRING;
}
{newline} {
throw make_error(yyextra->loc, "Unterminated string");
}
<<EOF>> {
throw make_error(yyextra->loc, "Unterminated string at EOF");
}
{STRINGCHAR}+ {
char *p = yytext;
while (*p) {
yyextra->loc.columns();
yyextra->str.push_back(*p++);
}
}
\\\" { yyextra->str.push_back('"'); }
\\\\ { yyextra->str.push_back('\\'); }
\\\/ { yyextra->str.push_back('/'); }
\\n { yyextra->str.push_back('\n'); }
\\t { yyextra->str.push_back('\t'); }
\\r { yyextra->str.push_back('\r'); }
\\b { yyextra->str.push_back('\b'); }
\\f { yyextra->str.push_back('\f'); }
\\u[0-9A-Fa-f]{4} {
int ch;
sscanf(yytext + 1, "%x", &ch);
yyextra->str.push_back(ch);
}
\\u { throw make_error(yyextra->loc, "bad Unicode escape sequence"); }
\\. { throw make_error(yyextra->loc, std::string("bad escape sequence \\") + yytext[1]); }
}
<LINE_COMMENT_STATE>{
{CRLF} { yyextra->loc.step(); BEGIN(INITIAL); }
{newline} { yyextra->loc.step(); BEGIN(INITIAL); }
{notnewline}+ /* eat comment character */
}
<INITIAL>{
{blank}+ { yyextra->loc.step(); }
{BOM}+ { yyextra->loc.step(); yyextra->loc.step(); yyextra->loc.step(); }
{CRLF}+ { yyextra->loc.lines(yyleng / 2); yyextra->loc.step(); }
{newline}+ { yyextra->loc.lines(yyleng); yyextra->loc.step(); }
# {yyextra->loc.step(); BEGIN(LINE_COMMENT_STATE); }
false { yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_FALSE; }
fragment { yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_FRAGMENT; }
mutation { yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_MUTATION; }
null { yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_NULL; }
on { yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_ON; }
query { yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_QUERY; }
true { yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_TRUE; }
{INTEGER} { yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_INTEGER; }
{FLOAT} { yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_FLOAT; }
{IDENTIFIER} { yylval->str = yytext; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_IDENTIFIER; }
{VARIABLE} { yylval->str = yytext + 1; *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_VARIABLE; }
"!" { *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_BANG; }
"(" { *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_LPAREN; }
")" { *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_RPAREN; }
"..." { *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_ELLIPSIS; }
":" { *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_COLON; }
"=" { *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_EQUAL; }
"@" { *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_AT; }
"[" { *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_LBRACKET; }
"]" { *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_RBRACKET; }
"{" { *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_LBRACE; }
"|" { *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_PIPE; }
"}" { *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_RBRACE; }
<<EOF>> { *yylloc = yyextra->loc; return yy::GraphQLParserImpl::token::TOK_EOF; }
\" {
BEGIN(STRING_STATE);
yyextra->str.clear();
}
}
<INITIAL,STRING_STATE,LINE_COMMENT_STATE>. {
char buf[6];
escape(yytext[0], buf);
throw make_error(
yyextra->loc,
std::string("unrecognized character ") + buf);
}
%%
static void escape(char c, char *buf) {
if (std::isgraph(c)) {
*buf = c;
buf[1] = '\0';
} else {
buf[0] = '\\';
buf[2] = '\0';
switch (c) {
case '\a':
buf[1] = 'a';
break;
case '\b':
buf[1] = 'b';
break;
case '\f':
buf[1] = 'f';
break;
case '\n':
buf[1] = 'n';
break;
case '\r':
buf[1] = 'r';
break;
case '\t':
buf[1] = 't';
break;
case '\v':
buf[1] = 'v';
break;
default:
buf[1] = 'x';
std::snprintf(buf + 2, 3, "%x", ((int)c & 0xFF));
break;
}
}
}