From a34a05d0d0146eabec855a1b34b476cfbe245d94 Mon Sep 17 00:00:00 2001 From: Eatswap Date: Fri, 9 Dec 2022 19:37:35 +0800 Subject: [PATCH] add: simple --- .clang-format | 2 +- DragonLisp.l | 58 ++++++++++++++++++++++++++++++ DragonLisp.y | 84 ++++++++++++++++++++++++++++++++++++++++++++ DragonLispDriver.cpp | 35 ++++++++++++++++++ DragonLispDriver.hh | 31 ++++++++++++++++ DragonLispScanner.hh | 35 ++++++++++++++++++ Makefile | 69 +++++++++++++++++++++++++++++++++--- main.cpp | 8 +++++ 8 files changed, 317 insertions(+), 5 deletions(-) create mode 100644 DragonLisp.l create mode 100644 DragonLisp.y create mode 100644 DragonLispDriver.cpp create mode 100644 DragonLispDriver.hh create mode 100644 DragonLispScanner.hh create mode 100644 main.cpp diff --git a/.clang-format b/.clang-format index 0bcdc29..b83efb6 100644 --- a/.clang-format +++ b/.clang-format @@ -1,4 +1,4 @@ -UseTab: true +UseTab: Always IndentWidth: 4 --- Language: Cpp diff --git a/DragonLisp.l b/DragonLisp.l new file mode 100644 index 0000000..f7c4591 --- /dev/null +++ b/DragonLisp.l @@ -0,0 +1,58 @@ +%{ + +#include +#include +#include + +#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(n); + return token::TOKEN_NUMBER; +}; + +{id} { /* return DragonLisp::DLParser::make_IDENTIFIER(yytext, *loc); */ } + +. { throw DragonLisp::DLParser::syntax_error(*loc, "Invalid character: " + std::string(yytext)); } + +<> { yyterminate(); } + +%% diff --git a/DragonLisp.y b/DragonLisp.y new file mode 100644 index 0000000..3fb428a --- /dev/null +++ b/DragonLisp.y @@ -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 +#include +#include + +#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 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); + } +} diff --git a/DragonLispDriver.cpp b/DragonLispDriver.cpp new file mode 100644 index 0000000..aba1dc1 --- /dev/null +++ b/DragonLispDriver.cpp @@ -0,0 +1,35 @@ +#include +#include + +#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 diff --git a/DragonLispDriver.hh b/DragonLispDriver.hh new file mode 100644 index 0000000..4ff9968 --- /dev/null +++ b/DragonLispDriver.hh @@ -0,0 +1,31 @@ +#ifndef __DRAGON_LISP_DRIVER_HH__ +#define __DRAGON_LISP_DRIVER_HH__ + +#include +#include + +#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__ diff --git a/DragonLispScanner.hh b/DragonLispScanner.hh new file mode 100644 index 0000000..33075b4 --- /dev/null +++ b/DragonLispScanner.hh @@ -0,0 +1,35 @@ +#ifndef __DRAGON_LISP_SCANNER_HH__ +#define __DRAGON_LISP_SCANNER_HH__ + +#ifndef yyFlexLexerOnce +#include +#endif + +#include + +#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__ \ No newline at end of file diff --git a/Makefile b/Makefile index 6c8f54a..1e2a695 100644 --- a/Makefile +++ b/Makefile @@ -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) diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..48997e1 --- /dev/null +++ b/main.cpp @@ -0,0 +1,8 @@ +#include + +#include "DragonLispDriver.hh" + +int main() { + DragonLisp::DLDriver driver; + return driver.parse(std::cin); +}