%top{
/*
* Scanner for C declarations.
* Copyright © 2011, 2021, 2023 Nick Bowler
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include
#include "parse.h"
}
%option nodefault noyywrap bison-locations reentrant never-interactive
%option extra-type="_Bool"
%option prefix="cdecl__yy"
%{
#include
#include "cdecl-internal.h"
#include "cdecl.h"
#if HAVE_STRTOUMAX
/* Best case, implementation provides strtoumax. */
# define STRTOUMAX strtoumax
#elif HAVE_STRTOULL
/* Fall back to strtoull, with possibly reduced range. */
#define STRTOUMAX strtoull
#elif HAVE___STRTOULL
/* HP-UX 11 has __strtoull in */
#define STRTOUMAX __strtoull
#else
/* Fall back to strtoul, with possibly reduced range. */
#define STRTOUMAX strtoul
#endif
#define lex_error(...) do { \
cdecl__err(CDECL_ENOPARSE, __VA_ARGS__); \
return T_LEX_ERROR; \
} while(0)
#define dup_token() do { \
yylval->strval = malloc(yyleng+1); \
if (!yylval->strval) { \
cdecl__err(CDECL_ENOMEM); \
return T_LEX_ERROR; \
} \
strcpy(yylval->strval, yytext); \
} while(0)
%}
%s ENGLISH
IDENT [_[:alpha:]][_[:alnum:]]*
INTEGER 0x[[:xdigit:]]+|0[0-7]+|[[:digit:]]+
%%
%{
if (yyextra) {
yyextra = 0;
BEGIN(ENGLISH);
return T_ENGLISH;
}
%}
"..." return T_ELLIPSIS;
";" return T_SEMICOLON;
"*" return T_ASTERISK;
"(" return T_LPAREN;
")" return T_RPAREN;
"[" return T_LBRACKET;
"]" return T_RBRACKET;
"," return T_COMMA;
"typedef" return T_TYPEDEF;
"extern" return T_EXTERN;
"static" return T_STATIC;
"auto" return T_AUTO;
"register" return T_REGISTER;
"restrict" return T_RESTRICT;
"volatile" return T_VOLATILE;
"const" return T_CONST;
"inline" return T_INLINE;
"void" return T_VOID;
"char" return T_CHAR;
"short" return T_SHORT;
"int" return T_INT;
"long" return T_LONG;
"float" return T_FLOAT;
"double" return T_DOUBLE;
"signed" return T_SIGNED;
"unsigned" return T_UNSIGNED;
"_Bool" return T_BOOL;
"_Complex" return T_COMPLEX;
"_Imaginary" return T_IMAGINARY;
"struct" return T_STRUCT;
"union" return T_UNION;
"enum" return T_ENUM;
{INTEGER} {
char *end;
errno = 0;
yylval->uintval = STRTOUMAX(yytext, &end, 0);
if (errno == ERANGE)
lex_error(_("integer constant out of range"));
if (*end)
lex_error(_("invalid integer constant"));
return T_UINT;
}
{
"variable-length" return T_VLA;
"type" return T_TYPE;
"declare" return T_DECLARE;
"pointer" return T_POINTER;
"function" return T_FUNCTION;
"returning" return T_RETURNING;
"array" return T_ARRAY;
"to" return T_TO;
"of" return T_OF;
"as" return T_AS;
}
{IDENT} { dup_token(); return T_IDENT; }
[[:space:]]+
. {
char buf[5] = { yytext[0] };
unsigned char c = buf[0];
if (!isprint(c) || c == '\\' || c == '\'') {
/* Encode nonprinting characters with C-style escapes */
buf[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;
case '\\': buf[1] = '\\'; break;
case '\'': buf[1] = '\''; break;
default:
buf[1] = '0' + ((c >> 6) & 3);
buf[2] = '0' + ((c >> 3) & 7);
buf[3] = '0' + ((c >> 0) & 7);
}
}
lex_error(_("syntax error, unexpected '%s'"), buf);
}