add: simple

This commit is contained in:
Eatswap 2022-12-09 19:37:35 +08:00
parent 7f2a90738b
commit a34a05d0d0
Signed by: Eatswap
GPG Key ID: BE661106A1F3FA0B
8 changed files with 317 additions and 5 deletions

View File

@ -1,4 +1,4 @@
UseTab: true
UseTab: Always
IndentWidth: 4
---
Language: Cpp

58
DragonLisp.l Normal file
View File

@ -0,0 +1,58 @@
%{
#include <cstdio>
#include <cstdint>
#include <iostream>
#include "DragonLispScanner.hh"
#undef YY_DECL
#define YY_DECL int DragonLisp::DLScanner::yylex(DragonLisp::DLParser::semantic_type* const lval, DragonLisp::DLParser::location_type* location, DragonLisp::DLDriver& drv)
using token = DragonLisp::DLParser::token;
#define yyterminate() return token::TOKEN_END;
#define YY_USER_ACTION loc->columns(yyleng);
%}
%option yyclass="DragonLisp::DLScanner"
%option verbose backup warn noyywrap c++ nounistd debug noline
id [a-zA-Z_][a-zA-Z_0-9]*
int [0-9]+
blank [ \t\v\r]
%%
%{
yylval = lval;
%}
{blank}+ { loc->step(); }
\n+ { loc->lines(yyleng); loc->step(); }
"(" { return token::TOKEN_LPAREN; }
")" { return token::TOKEN_RPAREN; }
"+" { return token::TOKEN_PLUS; }
"-" { return token::TOKEN_MINUS; }
"*" { return token::TOKEN_STAR; }
"/" { return token::TOKEN_SLASH; }
{int} {
errno = 0;
int64_t n = strtoll(yytext, nullptr, 10);
if (errno)
throw DragonLisp::DLParser::syntax_error(*loc, "Invalid integer provided: " + std::string(yytext));
yylval->emplace<int64_t>(n);
return token::TOKEN_NUMBER;
};
{id} { /* return DragonLisp::DLParser::make_IDENTIFIER(yytext, *loc); */ }
. { throw DragonLisp::DLParser::syntax_error(*loc, "Invalid character: " + std::string(yytext)); }
<<EOF>> { yyterminate(); }
%%

84
DragonLisp.y Normal file
View File

@ -0,0 +1,84 @@
%require "3.8.2"
%debug
%defines
%define api.namespace { DragonLisp }
%define api.parser.class { DLParser }
%code requires {
namespace DragonLisp {
class DLDriver;
class DLScanner;
}
}
%parse-param { DLScanner& scanner }
%param { DLDriver& drv }
%code {
#include <cstdio>
#include <cstdint>
#include <iostream>
#include "DragonLispDriver.hh"
#undef yylex
#define yylex scanner.yylex
}
%locations
%define api.token.prefix {TOKEN_}
%define api.value.type variant
%define parse.assert
%token
LPAREN "("
RPAREN ")"
PLUS "+"
MINUS "-"
STAR "*"
SLASH "/"
;
%token END 0 "EOF"
%token <int64_t> NUMBER "number"
%define parse.error verbose
%%
S
: R END
R
:
| R S-Expr
S-Expr
: LPAREN operator NUMBER NUMBER RPAREN { std::printf("This is S-Expr!\n"); }
operator
: PLUS { std::printf("I am plus +\n"); }
| MINUS { std::printf("I am minus -\n"); }
| STAR { std::printf("I am star *\n"); }
| SLASH { std::printf("I am slash /\n"); }
%%
void DragonLisp::DLParser::error(const location_type& l, const std::string& msg) {
std::cerr << "Error: " << msg << " at " << l << "\n";
}
DragonLisp::DLParser::symbol_type make_NUMBER(const std::string& s, const DragonLisp::DLParser::location_type& loc) {
try {
int n = std::stoi(s);
return DragonLisp::DLParser::make_NUMBER(n, loc);
} catch (...) {
throw DragonLisp::DLParser::syntax_error(loc, "Invalid integer provided: " + s);
}
}

35
DragonLispDriver.cpp Normal file
View File

@ -0,0 +1,35 @@
#include <fstream>
#include <string>
#include "DragonLispDriver.hh"
namespace DragonLisp {
DLDriver::~DLDriver() {
delete (this->scanner);
this->scanner = nullptr;
delete (this->parser);
this->parser = nullptr;
}
int DLDriver::parse(const std::string& f) {
std::ifstream in(f);
if (!in.good())
return 1;
return this->parse(in, f);
}
int DLDriver::parse(std::istream& in, const std::string& s) {
// Scanner
delete this->scanner;
this->scanner = new DLScanner(&in);
// Parser
delete this->parser;
this->parser = new DLParser(*this->scanner, *this);
this->parser->set_debug_level(1);
return this->parser->parse();
}
} // end namespace DragonLisp

31
DragonLispDriver.hh Normal file
View File

@ -0,0 +1,31 @@
#ifndef __DRAGON_LISP_DRIVER_HH__
#define __DRAGON_LISP_DRIVER_HH__
#include <string>
#include <istream>
#include "DragonLispScanner.hh"
#include "DragonLisp.tab.hh"
namespace DragonLisp {
class DLDriver {
public:
DLDriver() = default;
virtual ~DLDriver();
int parse(const std::string& f);
int parse(std::istream& in, const std::string& s = "stream input");
void error(const DLParser::location_type& l, const std::string& m);
void error(const std::string& m);
private:
DLParser* parser = nullptr;
DLScanner* scanner = nullptr;
DragonLisp::location location;
};
} // end namespace DragonLisp
#endif // __DRAGON_LISP_DRIVER_HH__

35
DragonLispScanner.hh Normal file
View File

@ -0,0 +1,35 @@
#ifndef __DRAGON_LISP_SCANNER_HH__
#define __DRAGON_LISP_SCANNER_HH__
#ifndef yyFlexLexerOnce
#include <FlexLexer.h>
#endif
#include <istream>
#include "DragonLisp.tab.hh"
#include "location.hh"
namespace DragonLisp {
class DLScanner : public yyFlexLexer {
private:
DragonLisp::DLParser::semantic_type* yylval = nullptr;
DragonLisp::DLParser::location_type* loc = nullptr;
public:
DLScanner(std::istream* in) : yyFlexLexer(in) {
this->loc = new DragonLisp::DLParser::location_type();
}
using FlexLexer::yylex;
virtual int yylex(
DragonLisp::DLParser::semantic_type* const lval,
DragonLisp::DLParser::location_type* location,
DragonLisp::DLDriver& drv
);
};
} // end namespace DragonLisp
#endif // __DRAGON_LISP_SCANNER_HH__

View File

@ -1,6 +1,67 @@
all:
echo "Working"
# I am a Makefile.
.PHONY: clean all
# Global
PROJ ?= DragonLisp
# Lexical Analysis
LEX = flex
LEXFLAGS ?= -T --hex
# Syntax Analysis
YACC = bison
YACCFLAGS ?= -Wall --color -v -t -d
LANG = c++
# Compile C/C++ Code
CC = gcc
CXX = g++
OUTPUT ?= $(PROJ).exe
COMMONFLAGS ?= -g -Wall
CFLAGS ?= $(COMMONFLAGS)
CXXFLAGS ?= $(COMMONFLAGS)
MISCOBJ = main DragonLispDriver
OBJS = $(addsuffix .o, $(MISCOBJ))
all: compile
lexer:
$(LEX) $(LEXFLAGS) $(PROJ).l
lexer_compile: lexer parser
$(CXX) $(CXXFLAGS) -c -o lexer.o lex.yy.cc
parser:
$(YACC) $(YACCFLAGS) --language=$(LANG) $(PROJ).y
parser_compile: parser
$(CXX) $(CXXFLAGS) -c -o parser.o $(PROJ).tab.cc
misc_compile: lexer parser
$(MAKE) $(OBJS)
compile: lexer_compile parser_compile misc_compile
$(CXX) $(CXXFLAGS) -o $(OUTPUT) $(OBJS) parser.o lexer.o $(LIBS)
compile_debug: lexer parser
$(CXX) $(CXXFLAGS) -o $(OUTPUT) \
main.cpp \
DragonLispDriver.cpp \
DragonLisp.tab.cc \
lex.yy.cc
clean:
echo "Cleaning"
rm -fv \
lex.backup \
lex.yy.cc \
$(PROJ).output \
$(PROJ).tab.cc \
$(PROJ).tab.hh \
stack.hh \
location.hh \
parser.o \
lexer.o \
$(OBJS) \
$(OUTPUT)

8
main.cpp Normal file
View File

@ -0,0 +1,8 @@
#include <iostream>
#include "DragonLispDriver.hh"
int main() {
DragonLisp::DLDriver driver;
return driver.parse(std::cin);
}