/* -*- mode: C -*- */ /* -------------------------------------------------------------------------- libconfig - A library for processing structured configuration files Copyright (C) 2005-2009 Mark A Lindner This file is part of libconfig. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, see . ---------------------------------------------------------------------------- */ %{ #define YY_EXTRA_TYPE void* %} %option nounistd %option reentrant %option noyywrap %option yylineno %option nounput %option bison-bridge %option header-file="scanner.h" %option outfile="lex.yy.c" %{ #ifdef _MSC_VER #pragma warning (disable: 4996) #endif #include #include #include #include "grammar.h" #include "wincompat.h" /* this is somewhat kludgy, but I wanted to avoid building strings dynamically during scanning */ static char *make_string(char *s) { char *r = ++s; char *p, *q = r; size_t len = strlen(r); int esc = 0; *(r + --len) = 0; for(p = r; *p; p++) { if(*p == '\\') { if(! esc) { esc = 1; continue; } } if(esc) { if(*p == 'n') *(q++) = '\n'; else if(*p == 'r') *(q++) = '\r'; else if(*p == 'f') *(q++) = '\f'; else if(*p == 't') *(q++) = '\t'; else *(q++) = *p; esc = 0; } else if(*p == '\"') /* if we reached the end of a string segment, ... */ { /* This construction allows for C-style string concatenation. We don't bother to check for end-of-string here, as we depend on the {string} definition to ensure a new opening quote exists. We do, however, check for and discard all forms of comments [that is, (#...$|//...$|[/][*]...[*][/])] between string segments. */ while (*++p != '\"') /* ... look for the start of the next segment */ { if(*p == '#') /* check for #...$ comment */ { while(*++p != '\n') { /* skip the rest of the line */ } } else if (*p == '/') { if(*++p == '/') /* check for //...$ comment */ { while (*++p != '\n') { /* skip the rest of the line */ } } else /* must be '*', lead-in to an old C-style comment */ { while (*++p != '*' || *(p+1) != '/') { /* skip all comment content */ } ++p; /* step to the trailing slash, to skip it as well */ } } } } else *(q++) = *p; } *q = 0; return(r); } static unsigned long long fromhex(const char *s) { #ifdef __MINGW32__ // MinGW's strtoull() seems to be broken; it only returns the lower // 32 bits... const char *p = s; unsigned long long val = 0; if(*p != '0') return(0); ++p; if(*p != 'x' && *p != 'X') return(0); for(++p; isxdigit(*p); ++p) { val <<= 4; val |= ((*p < 'A') ? (*p & 0xF) : (9 + (*p & 0x7))); } return(val); #else // ! __MINGW32__ return(strtoull(s, NULL, 16)); #endif // __MINGW32__ } %} ws [ \t\f\r\n]+ equals \=|\: comma , group_start \{ group_end \} true [Tt][Rr][Uu][Ee] false [Ff][Aa][Ll][Ss][Ee] name [A-Za-z\*][-A-Za-z0-9_\*]* quote \" integer [-+]?[0-9]+ integer64 [-+]?[0-9]+L(L)? hex 0[Xx][0-9A-Fa-f]+ hex64 0[Xx][0-9A-Fa-f]+L(L)? float ([-+]?([0-9]*)?\.[0-9]*([eE][-+]?[0-9]+)?)|([-+]?([0-9]+)(\.[0-9]*)?[eE][-+]?[0-9]+) segment {quote}([^\"\\]|\\.)*{quote} string {segment}(([ \t\f\r\n]*((#|\/\/).*\n|\/\*(.|\n)*\*\/)*)*{segment})* end ; array_start \[ array_end \] list_start \( list_end \) comment (#|\/\/).*$ %x COMMENT %% \/\* { BEGIN COMMENT; } \*\/ { BEGIN INITIAL; } . { /* ignore */ } \n { } {ws} { /* skip */ } {equals} { return(TOK_EQUALS); } {comma} { return(TOK_COMMA); } {group_start} { return(TOK_GROUP_START); } {group_end} { return(TOK_GROUP_END); } {true} { yylval->ival = 1; return(TOK_BOOLEAN); } {false} { yylval->ival = 0; return(TOK_BOOLEAN); } {name} { yylval->sval = strdup(yytext); return(TOK_NAME); } {float} { yylval->fval = atof(yytext); return(TOK_FLOAT); } {integer} { yylval->ival = atoi(yytext); return(TOK_INTEGER); } {integer64} { yylval->llval = atoll(yytext); return(TOK_INTEGER64); } {hex} { yylval->ival = strtoul(yytext, NULL, 16); return(TOK_HEX); } {hex64} { yylval->llval = fromhex(yytext); return(TOK_HEX64); } {string} { yylval->sval = strdup(make_string(yytext)); return(TOK_STRING); } {array_start} { return(TOK_ARRAY_START); } {array_end} { return(TOK_ARRAY_END); } {list_start} { return(TOK_LIST_START); } {list_end} { return(TOK_LIST_END); } {end} { return(TOK_END); } {comment} { /* ignore */ } . { return(TOK_GARBAGE); }