Skip to content

Commit

Permalink
Migrate scanner to C++ interface
Browse files Browse the repository at this point in the history
The C++ resource management is much easier and more secure. This
simplified the parse function and fixed a resource leak therein.
  • Loading branch information
coldfix committed May 9, 2015
1 parent 8bc5903 commit 6e4c187
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 41 deletions.
30 changes: 10 additions & 20 deletions citip.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
#include <math.h> // NAN
#include <utility> // move
#include <sstream> // istringstream

#include <glpk.h>

#include "citip.hpp"
#include "parser.hxx"
#include "scanner.hxx"
#include "scanner.hpp"

using std::move;

Expand Down Expand Up @@ -346,30 +347,19 @@ ShannonTypeProblem::ShannonTypeProblem(int num_vars)
ParserOutput parse(const std::vector<std::string>& exprs)
{
ParserOutput out;
yyscan_t scanner;
try {
yylex_init(&scanner);
for (auto&& line : exprs) {
yy::parser parser(scanner, &out);
YY_BUFFER_STATE buffer = yy_scan_bytes(line.c_str(), line.size(),
scanner);
int result = parser.parse();
if (result != 0) {
// Not sure if this can even happen
throw std::runtime_error("Unknown parsing error");
}
yy_delete_buffer(buffer, scanner);
for (auto&& line : exprs) {
std::istringstream in(line);
yy::scanner scanner(&in);
yy::parser parser(&scanner, &out);
int result = parser.parse();
if (result != 0) {
// Not sure if this can even happen
throw std::runtime_error("Unknown parsing error");
}
}
catch (...) {
yylex_destroy(scanner);
throw;
}

if (out.inquiries.empty()) {
throw std::runtime_error("undefined information expression");
}

return move(out);
}

Expand Down
14 changes: 10 additions & 4 deletions parser.y
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@
%require "3.0"

/* add parser members (scanner, cb) and yylex parameters (loc, scanner) */
%parse-param {yyscan_t scanner} {ParserCallback* cb}
%lex-param {yyscan_t scanner}
%parse-param {yy::scanner* scanner} {ParserCallback* cb}
%locations

/* increase usefulness of error messages */
Expand All @@ -43,7 +42,9 @@
#include "ast.hpp"
#include "location.hh"

typedef void* yyscan_t;
namespace yy {
class scanner;
};

// results
struct ParserCallback {
Expand All @@ -65,11 +66,16 @@
#include <utility> // move
#include <string>

#include "scanner.hxx" // yylex
#include "scanner.hpp"
#include "common.hpp" // sprint_all

using std::move;

#ifdef yylex
# undef yylex
#endif
#define yylex scanner->lex

template <class T, class V>
T&& enlist(T& t, V& v)
{
Expand Down
36 changes: 36 additions & 0 deletions scanner.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#ifndef __SCANNER_HPP__INCLUDED__
#define __SCANNER_HPP__INCLUDED__

#undef yyFlexLexer
#include <FlexLexer.h>
#include "parser.hxx"

// Tell flex which function to define
#ifdef YY_DECL
# undef YY_DECL
#endif
#define YY_DECL \
int yy::scanner::lex( \
yy::parser::semantic_type* yylval, \
yy::parser::location_type* yylloc)


namespace yy
{
// To feed data back to bison, the yylex method needs yylval and
// yylloc parameters. Since the yyFlexLexer class is defined in the
// system header <FlexLexer.h> the signature of its yylex() method
// can not be changed anymore. This makes it necessary to derive a
// scanner class that provides a method with the desired signature:

class scanner : public yyFlexLexer
{
public:
explicit scanner(std::istream* in=0, std::ostream* out=0);

int lex(parser::semantic_type* yylval,
parser::location_type* yylloc);
};
}

#endif // include guard
34 changes: 17 additions & 17 deletions scanner.l
Original file line number Diff line number Diff line change
Expand Up @@ -19,33 +19,22 @@
%option header-file="scanner.hxx"

/*
reentrant generate reentrant (thread-safe) parser
this adds the yyscanner argument to all functions
bison-bridge add &yylval argument to yylex
bison-locations add &yylloc argument to yylex
c++ generate C++ parser class
8bit don't fail on 8-bit input characters
warn warn about inconsistencies
nodefault don't create default echo-all rule
noyywrap don't use yywrap() function
*/
%option reentrant
%option bison-bridge
%option bison-locations

%option c++
%option 8bit warn nodefault
%option noyywrap

/* code that goes into the header as well as the implementation file */
%top {
#include "parser.hxx"

typedef yy::parser::semantic_type YYSTYPE;
typedef yy::parser::location_type YYLTYPE;
}

/* code that only goes into the implementation file */
%{
#include <stdexcept>
#include "parser.hxx"
#include "scanner.hpp"

// utility macros to simplify the actions
#define YIELD_TOKEN(tok, val, type) yylval->build<type>(val); \
return yy::parser::token::T_##tok;
Expand Down Expand Up @@ -95,3 +84,14 @@ H/\( LITERAL
. LITERAL

%%

yy::scanner::scanner(std::istream* in, std::ostream* out)
: yyFlexLexer(in, out)
{
}

int yyFlexLexer::yylex()
{
throw std::logic_error(
"The yylex() exists for technical reasons and must not be used.");
}

0 comments on commit 6e4c187

Please sign in to comment.