Commit 0ac2f44a authored by Alastair Robertson's avatar Alastair Robertson

Can build an AST

parent aaf4acf2
#pragma once
#include <string>
#include <vector>
namespace ebpf {
namespace bpftrace {
namespace ast {
class Node {
public:
virtual ~Node() { }
};
class Expression : public Node {
};
class Integer : public Expression {
public:
explicit Integer(int n) : n(n) { }
int n;
};
class Identifier : public Expression {
public:
explicit Identifier(std::string &ident) : ident(ident) { }
std::string ident;
};
class Statement : public Node {
public:
explicit Statement(Expression *expr) : expr(expr) { }
Expression *expr;
};
using StatementList = std::vector<Statement *>;
class PreProcessor : public Node {
public:
explicit PreProcessor(const std::string &line) : line(line) { }
std::string line;
};
using PreProcessorList = std::vector<PreProcessor *>;
class Probe : public Node {
public:
Probe(std::string type, std::string attach_point, StatementList *stmts)
: type(type), attach_point(attach_point), stmts(stmts) { }
std::string type;
std::string attach_point;
StatementList *stmts;
};
using ProbeList = std::vector<Probe *>;
class Program : public Node {
public:
Program(PreProcessorList *preprocs, ProbeList *probes)
: preprocs(preprocs), probes(probes) { }
PreProcessorList *preprocs;
ProbeList *probes;
};
} // namespace ast
} // namespace bpftrace
} // namespace ebpf
#pragma once
#include <istream>
#include "parser.tab.hh"
#include "ast.h"
#define YY_DECL ebpf::bpftrace::Parser::symbol_type yylex(ebpf::bpftrace::Driver &driver)
YY_DECL;
extern FILE *yyin;
namespace ebpf {
namespace bpftrace {
class Driver {
public:
Driver() : parser_(*this) { }
int parse()
{
return parser_.parse();
}
int parse(const std::string &f)
{
if (!(yyin = fopen(f.c_str(), "r"))) {
std::cerr << "Could not open file" << std::endl;
return -1;
}
return parser_.parse();
}
void error(const location &l, const std::string &m)
{
std::cerr << l << ": " << m << std::endl;
}
void error(const std::string &m)
{
std::cerr << m << std::endl;
}
ast::Program *root_;
private:
Parser parser_;
};
} // namespace bpftrace
} // namespace ebpf
%option yylineno nodefault noyywrap
%option never-interactive
%{
#include "driver.h"
#include "parser.tab.hh"
#undef yywrap
#define yywrap() 1
static ebpf::bpftrace::location loc;
#define YY_USER_ACTION loc.columns(yyleng);
#define yyterminate() return ebpf::bpftrace::Parser::make_END(loc)
using namespace ebpf::bpftrace;
%}
%%
%{
loc.step();
%}
[ \t]+ { loc.step(); }
[\n\r]+ { loc.lines(yyleng); loc.step(); }
"//".*$ // Comments
^"#".*$ { return Parser::make_PREPROCESSOR(yytext, loc); }
[_a-zA-Z][_a-zA-Z0-9]* { return Parser::make_IDENT(yytext, loc); }
[0-9]+ { return Parser::make_INT(strtoul(yytext, NULL, 0), loc); }
0[xX][0-9a-fA-F]+ { return Parser::make_INT(strtoul(yytext, NULL, 0), loc); }
":" { return Parser::make_COLON(loc); }
";" { return Parser::make_SEMI(loc); }
"{" { return Parser::make_LBRACE(loc); }
"}" { return Parser::make_RBRACE(loc); }
. { driver.error(loc, std::string("invalid character: ")+std::string(yytext)); yyterminate(); }
%%
#include "driver.h"
#include "ast.h"
int main(int argc, char *argv[])
{
int result;
ebpf::bpftrace::Driver driver;
if (argc == 1) {
result = driver.parse();
}
else {
result = driver.parse(argv[1]);
}
for (auto &preproc : *(driver.root_->preprocs)) {
std::cout << preproc->line << std::endl;
}
return result;
}
%skeleton "lalr1.cc"
%require "3.0.4"
%defines
%define api.namespace { ebpf::bpftrace }
%define parser_class_name { Parser }
%define api.token.constructor
%define api.value.type variant
%define parse.assert
%define parse.error verbose
%param { ebpf::bpftrace::Driver &driver }
%locations
// Forward declarations of classes referenced in the parser
%code requires
{
namespace ebpf {
namespace bpftrace {
class Driver;
namespace ast {
class Node;
} // namespace ast
} // namespace bpftrace
} // namespace ebpf
#include "ast.h"
}
%{
#include <iostream>
#include "driver.h"
void yyerror(ebpf::bpftrace::Driver &driver, const char *s);
%}
%define api.token.prefix {TOK_}
%token
END 0 "end of file"
COLON ":"
SEMI ";"
LBRACE "{"
RBRACE "}"
;
%token <std::string> PREPROCESSOR "preprocessor"
%token <std::string> IDENT "identifier"
%token <int> INT "integer"
%type <ast::PreProcessorList *> preprocs
%type <ast::ProbeList *> probes
%type <ast::StatementList *> block stmts
%type <ast::Probe *> probe
%type <ast::Statement *> stmt
%type <ast::Expression *> expr
%printer { yyoutput << %%; } <*>;
%start program
%%
program : preprocs probes { driver.root_ = new ast::Program($1, $2); }
| probes
;
preprocs : preprocs PREPROCESSOR { $$ = $1; $1->push_back(new ast::PreProcessor($2)); }
| PREPROCESSOR { $$ = new ast::PreProcessorList;
$$->push_back(new ast::PreProcessor($1)); }
probes : probes probe { $$ = $1; $1->push_back($2); }
| probe { $$ = new ast::ProbeList;
$$->push_back($1); }
;
probe : IDENT ":" IDENT block { $$ = new ast::Probe($1, $3, $4); }
;
block : "{" stmts "}" { $$ = $2; }
| "{" stmts ";" "}" { $$ = $2; }
stmts : stmts ";" stmt { $$ = $1; $1->push_back($3); }
| stmt { $$ = new ast::StatementList; $$->push_back($1); }
;
stmt : expr { $$ = new ast::Statement($1); }
;
expr : INT { $$ = new ast::Integer($1); }
| IDENT { $$ = new ast::Identifier($1); }
;
%%
void ebpf::bpftrace::Parser::error(const location &l, const std::string &m)
{
driver.error(l, m);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment