cgal/Circular_kernel_2/benchmark/parser/benchmark_lexer.l

408 lines
16 KiB
Plaintext

/**************************************************************************
// Copyright (c) 2004 Max-Planck-Institut Saarbruecken (Germany)
// All rights reserved.
//
// This file is part of BenchmarkParser
//
// $URL$
// $Id$
// SPDX-License-Identifier: LGPL-3.0-or-later
//
//
// Author(s) : Lutz Kettner
**************************************************************************/
%{
#include <string>
#include <list>
#include <iostream>
#include <iomanip>
#include <fstream>
/* Use C++ std::string as semantic value to communicate with lexer */
#define YYSTYPE std::string
#include <benchmark_parser.tab.h> // gets definitions from syntax parser
// Public lexer interface, check with decl. in benchmark_parser.h
// --------------------------------------------------------------
// Current input stream and associated values.
std::istream* benchmark_in = & std::cin;
int benchmark_linenumber = 1;
std::string benchmark_filename( "<cin>");
// Initialize lexer to scan from input stream with name and linenumber.
// The caller is responsible for the lifetime of 'in' that must live
// during the scan.
void benchmark_init_lexer(
std::istream& in, std::string name, int linenumber = 1);
// Reset lexer to clean state.
void benchmark_reset_lexer();
// Writes a trace of the current include file nesting to the 'out' stream.
// Appends the 'fill' string after each file listed.
void benchmark_include_file_trace( std::ostream& out, std::string fill);
// Private lexer interface, all static to keep it local
// ----------------------------------------------------
// Stack of input streams: the item stored in the stack.
struct Include_stack_item {
std::istream* in; // input stream
int linenumber; // linenumber in file for error messages
std::string filename; // filename (or similar string)
YY_BUFFER_STATE buffer; // Opaque pointer to flex-buffer struct.
Include_stack_item() {}
Include_stack_item( std::istream* i, int ln, std::string name,
YY_BUFFER_STATE buf)
: in(i), linenumber(ln), filename(name), buffer(buf) {}
};
// Stack of input streams is a std::list
typedef std::list<Include_stack_item> Include_stack;
// We have one static global variable for the stack and some static functions.
// The include stack is except for the trace() debug function not
// accessible from other files (is not polluting namespaces) since
// the Include() function and the <<EOF>> condition are all handled here.
// The function implementations are at the end of this file.
static Include_stack include_stack;
// Push current state on include_stack, initializes lexer with new file
// input stream, name, and linenumber.
static void open_include_stream(
std::istream *in, std::string name, int linenumber = 1);
// Shortcut for open file with name and then call open_include_stream.
// Returns false if the file could not be opened successfully.
static bool open_include_file( std::string name, int linenumber = 1);
// Closes current input stream. Initializes lexer with new file input stream,
// name, and linenumber, from the include_stack's top. Pop's an element from
// the include_stack. Returns false if include_stack was empty.
static bool close_include_stream();
// Make the lexer read from benchmark_in instead of yyin
#define YY_INPUT(buf,result,max_size) { \
benchmark_in->read( buf, max_size); \
result = benchmark_in->gcount(); \
}
// Count newlines in the string s
static void count_newlines( const char* s) {
while ( *s) {
if ( *s == '\n')
++benchmark_linenumber;
++s;
}
}
static int comment_nesting = 0; // counts nesting depth of () in Comments
#define YY_BREAK /* a do nothing */
/* --------------------------------------------------------------------
Parsing Modes:
-- INITIAL: main mode for sequence of tokens
-- IncludeMode: parses lciInclude filename,
-- CommentMode: Comment(...) parsing of nested parantheses
# comments and strings are correctly ignored
-------------------------------------------------------------------- */
%}
%x IncludeMode
%x CommentMode
space [\t \r]*
newline [\n]
spcnl [\t \n\r]*
integer [+-]?[0-9]+
/* An fnumber consists of up to three parts:
* 1) a sign [+-]
* 2) a mantissa (digits [0-9] with at most one dot in between)
* 3) an exponent [eE]{integer}
*
* Part 1) is optional.
* Part 2) must contain at least one digit,
* but may have leading or trailing dot
* Part 3) is optional iff the mantissa contains a dot
* (so that fnumbers and integers remain distinguishable).
*/
fnumber [+-]?(([0-9]+[.][0-9]*|[.][0-9]+)([eE]{integer})?|[0-9]+[eE]{integer})
idfier [a-zA-Z][a-zA-Z0-9_]*
minus_infty MINUS_INFTY
plus_infty PLUS_INFTY
filename [^ \t\n\r\\\{\}\[\]()]+
void VOID
counterclockwise COUNTERCLOCKWISE
clockwise CLOCKWISE
%%
/* Tokens */
/* --------- */
"FileFormat" { return FileFormat;}
"BenchmarkName" { return BenchmarkName; }
"Classification" { return Classification; }
"List" { return List; }
"Rational" { return Rational; }
"Polynomial_1" { return Polynomial_1; }
"Point_2" { return Point_2; }
"AlgebraicReal" { return AlgebraicReal; }
"ConicPoint_2" { return ConicPoint_2; }
"Conic_2" { return Conic_2; }
"ConicArc_2" { return ConicArc_2; }
"Circle_2" { return Circle_2; }
"LineSegment_2" { return LineSegment_2; }
"Cubic_2" { return Cubic_2; }
"CircularArc_2" { return CircularArc_2;}
"LineArc_2" { return LineArc_2;}
"CircularPoint_2" {return CircularPoint_2;}
"Quadric_3" { return Quadric_3; }
/* Integer numbers and float numbers */
/* --------------------------------- */
{integer} { yylval = std::string( yytext);
return INTEGER;
}
{fnumber} { yylval = std::string( yytext);
return FNUMBER;
}
{minus_infty} { yylval = std::string( yytext);
return MINUS_INFTY;
}
{plus_infty} { yylval = std::string( yytext);
return PLUS_INFTY;
}
{void} { yylval = std::string( yytext);
return VOID;
}
{counterclockwise} { yylval = std::string( yytext);
return COUNTERCLOCKWISE;
}
{clockwise} { yylval = std::string( yytext);
return CLOCKWISE;
}
/* Non-recognized tokens are errors */
/* -------------------------------- */
{idfier} { yylval = std::string( yytext);
return UNKNOWN_TOKEN;
}
/* Handle include files */
/* ------------------------- */
"IncludeFile"{spcnl}[(]{spcnl} { BEGIN( IncludeMode);
count_newlines( yytext);
break;
}
<IncludeMode>{filename} { /* remove remaining chars before the ')' */
int c = yyinput();
while( c != EOF && c != ')') {
if ( c == '\n')
++benchmark_linenumber;
c = yyinput();
}
BEGIN( INITIAL);
if ( c == EOF) {
yylval = std::string( "Reached EOF while"
" parsing include filename '") +
std::string( yytext) +
std::string( "'.");
return ERROR;
}
open_include_file( yytext);
break;
}
/* Strings with quoted \" and \\ */
/* ------------------------------ */
<INITIAL,CommentMode>"\"" { int c = yyinput();
yylval = std::string("");
bool quoted_char = false;
while (c != EOF && (c!='"' || quoted_char)){
if ( c == '\n')
++benchmark_linenumber;
if ( ! quoted_char && c == '\\') {
quoted_char = true;
} else {
quoted_char = false;
yylval.push_back( char(c));
}
c = yyinput();
}
if ( c == EOF) {
yylval = std::string( "Reached EOF while"
" parsing string constant '") +
yylval + std::string( "'.");
BEGIN( INITIAL);
return ERROR;
}
if ( YY_START == INITIAL) {
return STRING;
}
yylval = std::string("");
break;
}
/* One line comment starting with # */
/* -------------------------------- */
<INITIAL,CommentMode>"#" { /* remove remaining chars before the '\n' */
int c = yyinput();
while( c != EOF && c != '\n') {
c = yyinput();
}
if ( c == '\n')
++benchmark_linenumber;
break;
}
/* Nestable and multi-line Comment( ... ) */
/* -------------------------------------- */
"Comment"{spcnl}"("{spcnl} { BEGIN( CommentMode);
comment_nesting = 1;
count_newlines( yytext);
break;
}
<CommentMode>{newline} { ++benchmark_linenumber; break; }
<CommentMode>"(" { ++comment_nesting; break; }
<CommentMode>")" { if ( --comment_nesting == 0)
BEGIN( INITIAL);
break;
}
<CommentMode><<EOF>> { yylval = std::string( "Reached EOF while "
"parsing 'Comment(...)'.");
BEGIN( INITIAL);
return ERROR;
}
<CommentMode>. { break; }
/* Count line numbers for good error messages */
{newline} { ++benchmark_linenumber; break; }
/* Ignore white spaces */
{space} { break; }
/* stop scanning at EOF, maybe continue with surrounding file */
<<EOF>> { yyterminate(); }
/* single characters passed to the parser: */
[(),] { return yytext[0]; }
/* all other single characters are errors */
. { yylval = std::string( "Found illegal char '")
+ std::string( yytext) + std::string("'.");
return ERROR;
}
%%
// implements the proper EOF behavior, pop's file from include stack
extern "C" int yywrap() {
if ( close_include_stream())
return 0; // there was a file waiting on the stack, we continue scan
return 1; // no file in the stack left, we stop scan
}
// Push current state on include_stack, initializes lexer with new file
// input stream, name, and linenumber.
static void open_include_stream( std::istream *in, std::string name,
int linenumber)
{
include_stack.push_front( Include_stack_item(
benchmark_in, benchmark_linenumber, benchmark_filename,
YY_CURRENT_BUFFER));
benchmark_in = in;
benchmark_linenumber = linenumber;
benchmark_filename = name;
yy_switch_to_buffer( yy_create_buffer( 0, YY_BUF_SIZE));
}
// Shortcut for open file with name and then call open_include_stream.
// Returns false if the file could not be opened successfully.
static bool open_include_file( std::string name, int linenumber) {
std::ifstream* in = new std::ifstream( name.c_str());
if ( ! *in) {
delete in;
return false;
}
open_include_stream( in, name, linenumber);
return true;
}
// Closes current input stream. Initializes lexer with new file input stream,
// name, and linenumber, from the include_stack's top. Pop's an element from
// the include_stack. Returns false if include_stack was empty.
static bool close_include_stream() {
if ( include_stack.empty())
return false;
delete benchmark_in; // closes the stream
benchmark_in = include_stack.front().in;
benchmark_linenumber = include_stack.front().linenumber;
benchmark_filename = include_stack.front().filename;
yy_delete_buffer( YY_CURRENT_BUFFER);
yy_switch_to_buffer( include_stack.front().buffer);
include_stack.pop_front();
return true;
}
// Public interface of the lexer component
// ---------------------------------------
// Initialize lexer to scan from input stream with name and linenumber.
// The caller is responsible for the lifetime of 'in' that must last
// during the scan.
void benchmark_init_lexer(
std::istream& in, std::string name, int linenumber)
{
benchmark_reset_lexer();
benchmark_in = & in;
benchmark_linenumber = linenumber;
benchmark_filename = name;
yy_switch_to_buffer( yy_create_buffer( 0, YY_BUF_SIZE));
}
// reset lexer to clean state. Can be used to parse another file then.
void benchmark_reset_lexer() {
while( close_include_stream()) // close all pre-existing include files
; // empty while body
benchmark_in = & std::cin;
benchmark_linenumber = 1;
benchmark_filename = std::string("<cin>");
yyrestart(0);
BEGIN( INITIAL);
};
// Writes a trace of the current include file nesting to the 'out' stream.
void benchmark_include_file_trace( std::ostream& out, std::string fill) {
std::size_t n = include_stack.size();
for ( Include_stack::const_iterator i = include_stack.begin();
i != include_stack.end(); ++i)
{
out << std::setw(3) << n-- << ": '" << i->filename << "' line "
<< i->linenumber << fill << std::endl;
}
}
// This summy function is only here to suppress a warning for
// an unused yyunput function
void benchmark_parser_dummy_no_warn_() {
yyunput( 1, 0);
}
// EOF