Skip to content

Commit

Permalink
Rearrange preambles in scanner/parser modules
Browse files Browse the repository at this point in the history
Put the flex/bison options on top, implementation details below.

Also add some comments.
  • Loading branch information
coldfix committed May 8, 2015
1 parent 87191c5 commit 2d0dea4
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 32 deletions.
4 changes: 4 additions & 0 deletions ast.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
#ifndef __AST_HPP__INCLUDED__
#define __AST_HPP__INCLUDED__

// This file defines the AST (abstract syntax tree) for the Citip grammar,
// i.e. the data structures that hold all the information from the parsed
// input statements.

# include <string>
# include <vector>

Expand Down
40 changes: 30 additions & 10 deletions parser.y
Original file line number Diff line number Diff line change
@@ -1,13 +1,40 @@
/*
* Bison parser definition.
Bison parser definition.
For those who are new to flex/bison:
This file is transpiled (using 'bison parser.y') to a .cpp file that
implements the class yy::parser. This class has the job to analyze the
token stream resulting from repeated invocation of the yylex() function
and create an AST (abstract syntax tree) of the given string expressions.
Actually, the grammar is quite simple (in fact it is regular) and does
not require this level of parsing power, but using bison was a nice
getting-to-know exercise and makes language easier to extend and the code
easier to maintain (I believe).
Indeed, I'm a bit fond of the nice usage of C++11 initializer lists to
reduce redundancy in the AST composition code - which I hadn't seen in
any example so far.
*/

%output "parser.cpp"
%defines "parser.hpp"

/* C++ parser interface */
%skeleton "lalr1.cc"
%require "3.0"

%output "parser.cpp"
%defines "parser.hpp"
/* add parser members (scanner, cb) and yylex parameters (loc, scanner) */
%parse-param {yyscan_t scanner} {ParserCallback* cb}
%lex-param {yyscan_t scanner}
%locations

/* increase usefulness of error messages */
%define parse.error verbose

/* assert correct cleanup of semantic value objects */
%define parse.assert

%code requires {
#include "ast.hpp"
Expand Down Expand Up @@ -35,15 +62,8 @@
t.push_back(move(v));
return move(t);
}

}

%lex-param {yyscan_t scanner}
%parse-param {yyscan_t scanner} {ParserCallback* cb}
%locations
%error-verbose
%define parse.assert

%define api.value.type variant
%define api.token.prefix {T_}

Expand Down
57 changes: 35 additions & 22 deletions scanner.l
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,18 @@
Flex scanner (also known as lexer/lexical analyzer or tokenizer) for the
Citip grammar. The scanner transforms a byte input stream into a stream
of tokens.
*/
%top {
#include "parser.hpp"

typedef yy::parser::semantic_type YYSTYPE;
typedef yy::parser::location_type YYLTYPE;
}
For those who are new to flex/bison:
%{
#define YIELD_TOKEN(tok, val, type) yylval->build<type>(val); \
return yy::parser::token::T_##tok;
This file is transpiled (using 'flex scanner.l') to a .cpp source file
which implements a tokenizer function that returns on each call the
integer tag of a token and stores additional information into its output
parameters. The function declaration looks as follows:
#define YY_TXT std::string(yytext, yyleng)
#define YY_NUM std::atof(yytext)

#define INT_TOKEN(tok, val) YIELD_TOKEN(tok, val, int)
#define NUM_TOKEN(tok) YIELD_TOKEN(tok, YY_NUM, double)
#define STR_TOKEN(tok) YIELD_TOKEN(tok, YY_TXT, std::string)
#define LITERAL return yytext[0];

#define YY_USER_ACTION yylloc->columns(yyleng);

%}
int yylex(parser::semantic_type* yylval_param, // [out]
parser::location_type* yylloc_param, // [in/out]
yyscan_t yyscanner) // scanner object
*/

%option outfile="scanner.cpp"
%option header-file="scanner.hpp"
Expand All @@ -48,8 +36,34 @@
%option 8bit warn nodefault
%option noyywrap

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

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

/* code that only goes into the implementation file */
%{
// utility macros to simplify the actions
#define YIELD_TOKEN(tok, val, type) yylval->build<type>(val); \
return yy::parser::token::T_##tok;

#define YY_TXT std::string(yytext, yyleng)
#define YY_NUM std::atof(yytext)

#define INT_TOKEN(tok, val) YIELD_TOKEN(tok, val, int)
#define NUM_TOKEN(tok) YIELD_TOKEN(tok, YY_NUM, double)
#define STR_TOKEN(tok) YIELD_TOKEN(tok, YY_TXT, std::string)
#define LITERAL return yytext[0];

#define YY_USER_ACTION yylloc->columns(yyleng);
%}

%%

/* code to be executed at every yylex() call */
%{
yylloc->step();
%}
Expand All @@ -73,7 +87,6 @@ H/\( LITERAL
#.* {/* eat comments */}
[ \t] {/* eat whitespace */}


\n yylloc->lines(1); LITERAL

/* forward everything else, even invalid
Expand Down

0 comments on commit 2d0dea4

Please sign in to comment.