This commit is contained in:
bronku 2025-11-18 15:36:34 +01:00
commit 080d115e17
6 changed files with 202 additions and 0 deletions

22
src/ParserCtx.cpp Normal file
View file

@ -0,0 +1,22 @@
#include "ParserCtx.hpp"
#include "../build/lexer.hpp"
#include "../build/parser.hpp"
namespace Elite
{
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;
}
} // namespace Elite

23
src/ParserCtx.hpp Normal file
View file

@ -0,0 +1,23 @@
#pragma once
namespace yy
{
class Parser;
class location;
}
namespace Elite
{
class ParserCtx
{
public:
ParserCtx();
~ParserCtx();
void *lexer;
yy::location *loc;
yy::Parser *parser;
};
} // namespace Elite

46
src/lexer.l Normal file
View file

@ -0,0 +1,46 @@
%option reentrant noyywrap nounput
%{
#include <iostream>
#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)
#include "../build/parser.hpp"
%}
/* your definitions here */
/* your definitions end */
%%
%{
loc.step();
%}
/* your rules here */
/* use this structure to pass the Token :
* return yy::parser::make_TokenName(loc)
* if the token has a type you can pass it's value
* as the first argument. as an example we put
* the rule to return token function.
*/
function {return yy::Parser::make_FUNCTION(loc);}
[ \n\r\t\v] {}
. {std::cerr << loc << ": " << "token error" << std::endl; exit(1);}
/* if you didn't define #define yyterminate() at beginnign, you will need
this rule to match the end of file */
/* <<EOF>> {return yy::Parser::make_END(loc);} */
/* your rules end */
%%

86
src/parser.y Normal file
View file

@ -0,0 +1,86 @@
/* Require bison minimal version */
%require "3.0.4"
/* use newer C++ skeleton file */
%skeleton "lalr1.cc"
/* write out a header file containing the token defines */
%defines
/* namespace to enclose parser in */
%name-prefix="yy"
/* set the parser's class identifier */
%define api.parser.class {Parser}
/* it will generate a location class which can be used in your lexer */
%locations
/* use the constructor for each token, and make_TOKENNAME functions will be generated */
%define api.token.constructor
/* use the variant type for $1~$n and $$ those variables */
%define api.value.type variant
%define parse.trace
%define parse.error verbose
%code requires
{
/* you may need these header files
* add more header file if you need more
*/
#include <list>
#include <string>
#include <functional>
#include "../src/ParserCtx.hpp"
/* define the sturctures using as types for non-terminals */
/* end the structures for non-terminal types */
}
%code
{
yy::Parser::symbol_type yylex(void* yyscanner, yy::location& loc);
}
%token END 0;
/* specify tokens, type of non-terminals and terminals here */
%token FUNCTION
/* end of token specifications */
/* 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 Elite::ParserCtx& ctx }
%%
%start program;
program: FUNCTION;
%%
int main(int argc, char *argv[])
{
Elite::ParserCtx ctx;
return ctx.parser->parse();
}
void yy::Parser::error(const yy::location& l, const std::string& m)
{
std::cerr << l << ": " << m << std::endl;
}