simpliest c++ example
This commit is contained in:
parent
d587646b32
commit
909a43114b
9 changed files with 73 additions and 221 deletions
|
|
@ -1,18 +0,0 @@
|
|||
#include "ParserCtx.hpp"
|
||||
#include "../build/lexer.hpp"
|
||||
#include "../build/parser.hpp"
|
||||
|
||||
ParserCtx::ParserCtx()
|
||||
{
|
||||
yylex_init(&lexer);
|
||||
// yyset_in()
|
||||
loc = new yy::location();
|
||||
parser = new yy::Parser(lexer, *loc, *this);
|
||||
}
|
||||
|
||||
ParserCtx::~ParserCtx()
|
||||
{
|
||||
yylex_destroy(lexer);
|
||||
delete loc;
|
||||
delete parser;
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
namespace yy
|
||||
{
|
||||
class Parser;
|
||||
class location;
|
||||
}
|
||||
|
||||
class ParserCtx
|
||||
{
|
||||
public:
|
||||
ParserCtx();
|
||||
~ParserCtx();
|
||||
|
||||
void *lexer;
|
||||
yy::location *loc;
|
||||
yy::Parser *parser;
|
||||
};
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
#include "config.hpp"
|
||||
#include <unistd.h>
|
||||
#include <stdexcept>
|
||||
|
||||
Configuration::Configuration(int argc, char **argv)
|
||||
{
|
||||
int opt;
|
||||
while ((opt = getopt(argc, argv, "i:o:l")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'i':
|
||||
input_file = optarg;
|
||||
break;
|
||||
case 'o':
|
||||
output_file = optarg;
|
||||
break;
|
||||
case 'l':
|
||||
debug_lexer = true;
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Invalid arguments");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
|
||||
class Configuration
|
||||
{
|
||||
public:
|
||||
std::string input_file;
|
||||
std::string output_file;
|
||||
bool debug_lexer = false;
|
||||
|
||||
Configuration(int argc, char **argv);
|
||||
};
|
||||
45
src/lexer.l
45
src/lexer.l
|
|
@ -1,28 +1,35 @@
|
|||
%option reentrant noyywrap nounput
|
||||
%option c++
|
||||
%option noyywrap
|
||||
%option yyclass="Scanner"
|
||||
|
||||
%{
|
||||
#include <iostream>
|
||||
#include "../build/parser.hpp"
|
||||
#include <string>
|
||||
|
||||
#define YY_DECL yy::Parser::symbol_type yylex(yyscan_t yyscanner, yy::location& loc)
|
||||
|
||||
#define YY_USER_ACTION loc.columns(yyleng);
|
||||
#define yyterminate() return yy::Parser::make_END(loc)
|
||||
class Scanner : public yyFlexLexer {
|
||||
public:
|
||||
Scanner(std::istream* in) : yyFlexLexer(in) {}
|
||||
|
||||
int yylex();
|
||||
|
||||
int lex(yy::parser::semantic_type* yylval) {
|
||||
this->yylval = yylval;
|
||||
return yylex();
|
||||
}
|
||||
|
||||
private:
|
||||
yy::parser::semantic_type* yylval;
|
||||
};
|
||||
|
||||
int scanner_lex(yy::parser::semantic_type* yylval) {
|
||||
static Scanner scanner(&std::cin);
|
||||
return scanner.lex(yylval);
|
||||
}
|
||||
%}
|
||||
|
||||
%%
|
||||
|
||||
%{
|
||||
loc.step();
|
||||
%}
|
||||
|
||||
|
||||
function {return yy::Parser::make_FUNCTION(loc);}
|
||||
|
||||
[ \n\r\t\v] {}
|
||||
|
||||
. {std::cerr << loc << ": " << "token error" << std::endl; exit(1);}
|
||||
|
||||
%%
|
||||
[0-9]+ { return yy::parser::token::TOK_NUMBER; }
|
||||
[a-zA-Z]+ { yylval->as<std::string>() = yytext; return yy::parser::token::TOK_WORD; }
|
||||
[ \t\r\n]+ { /* skip */ }
|
||||
. { return yy::parser::token::TOK_CHAR; }
|
||||
%%
|
||||
40
src/main.cpp
40
src/main.cpp
|
|
@ -1,41 +1,7 @@
|
|||
#include "../build/parser.hpp"
|
||||
#include "../build/lexer.hpp"
|
||||
#include "../src/config.hpp"
|
||||
#include "../src/ParserCtx.hpp"
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
yy::Parser::symbol_type yylex(yyscan_t yyscanner, yy::location &loc);
|
||||
|
||||
void dump_tokens(ParserCtx &ctx)
|
||||
int main()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
auto tok = yylex(ctx.lexer, *ctx.loc);
|
||||
|
||||
std::cout
|
||||
<< "Token: "
|
||||
<< yy::Parser::symbol_name(tok.kind())
|
||||
<< ", Location: " << tok.location
|
||||
<< '\n';
|
||||
|
||||
if (tok.kind() == yy::Parser::symbol_kind::S_YYEOF)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
ParserCtx ctx;
|
||||
Configuration config(argc, argv);
|
||||
|
||||
if (config.debug_lexer)
|
||||
{
|
||||
dump_tokens(ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return ctx.parser->parse();
|
||||
yy::parser p;
|
||||
return p.parse();
|
||||
}
|
||||
72
src/parser.y
72
src/parser.y
|
|
@ -1,51 +1,45 @@
|
|||
%require "3.0.4"
|
||||
%skeleton "lalr1.cc"
|
||||
%defines
|
||||
%define api.prefix {yy}
|
||||
%define api.parser.class {Parser}
|
||||
%locations
|
||||
%define api.token.constructor
|
||||
%skeleton "lalr1.cc"
|
||||
%require "3.0"
|
||||
%defines
|
||||
%define api.value.type variant
|
||||
%define parse.trace
|
||||
%define parse.error verbose
|
||||
%define api.parser.class { parser }
|
||||
%define api.namespace { yy }
|
||||
%define api.token.prefix {TOK_}
|
||||
|
||||
|
||||
%code requires
|
||||
{
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include "../src/ParserCtx.hpp"
|
||||
%code requires {
|
||||
#include <string>
|
||||
}
|
||||
|
||||
%code
|
||||
{
|
||||
yy::Parser::symbol_type yylex(void* yyscanner, yy::location& loc);
|
||||
%code {
|
||||
#include <iostream>
|
||||
|
||||
int scanner_lex(yy::parser::semantic_type* yylval);
|
||||
|
||||
#undef yylex
|
||||
#define yylex scanner_lex
|
||||
}
|
||||
|
||||
%token <std::string> WORD
|
||||
%token NUMBER
|
||||
%token CHAR
|
||||
|
||||
%token END 0;
|
||||
%token FUNCTION
|
||||
|
||||
|
||||
/* The driver is passed by reference to the parser and to the scanner. This
|
||||
* provides a simple but effective pure interface, not relying on global
|
||||
* variables. */
|
||||
%lex-param {void *scanner} {yy::location& loc}
|
||||
%parse-param {void *scanner} {yy::location& loc} { class ParserCtx& ctx }
|
||||
|
||||
%%
|
||||
input:
|
||||
/* empty */
|
||||
| input element
|
||||
;
|
||||
|
||||
element:
|
||||
WORD { std::cout << "WORD: " << $1 << "\n"; }
|
||||
| NUMBER { std::cout << "NUMBER\n"; }
|
||||
| CHAR { std::cout << "CHAR\n"; }
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
%start program;
|
||||
|
||||
program: FUNCTION;
|
||||
|
||||
|
||||
%%
|
||||
|
||||
void yy::Parser::error(const yy::location& l, const std::string& m)
|
||||
{
|
||||
std::cerr << l << ": " << m << std::endl;
|
||||
namespace yy {
|
||||
void parser::error(const std::string& msg)
|
||||
{
|
||||
std::cerr << "Error: " << msg << "\n";
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue