From 278cff8075ea747312cf9f15bdb03e883f2e7cc2 Mon Sep 17 00:00:00 2001 From: Moore <837016156@qq.com> Date: Mon, 27 Jul 2020 21:13:52 +0800 Subject: [PATCH] =?UTF-8?q?=E8=AF=8D=E6=B3=95=E5=88=86=E6=9E=90=E5=9F=BA?= =?UTF-8?q?=E7=A1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/character_util.hpp | 11 ++++ src/exceptions.hpp | 23 +++++++ src/main.cpp | 23 +++---- src/parser.cpp | 142 ++++++++++++++++++++++++++++++++++++----- src/parser.h | 55 +++++++++++++--- src/string_util.hpp | 25 ++++++++ test/helloworld.fpp | 2 +- 7 files changed, 241 insertions(+), 40 deletions(-) create mode 100644 src/character_util.hpp create mode 100644 src/exceptions.hpp create mode 100644 src/string_util.hpp diff --git a/src/character_util.hpp b/src/character_util.hpp new file mode 100644 index 0000000..b6f6a40 --- /dev/null +++ b/src/character_util.hpp @@ -0,0 +1,11 @@ +#pragma once + +namespace parser { + +bool is_lower_case_letter(char c) {return c >= 'a' && c <= 'z';}; +bool is_capital_letter(char c) {return c >= 'A' && c <= 'Z';}; +bool is_number_character(char c) {return c >= '0' && c <= '9';}; +bool is_letter(char c) {return is_lower_case_letter(c) || is_capital_letter(c);} +bool is_blank(char c) {return c == ' ' || c == '\t' || c == '\r' || c == '\n';} + +} // namespace parser \ No newline at end of file diff --git a/src/exceptions.hpp b/src/exceptions.hpp new file mode 100644 index 0000000..955c660 --- /dev/null +++ b/src/exceptions.hpp @@ -0,0 +1,23 @@ +#include +#include +#include "string_util.hpp" + +#define DEFINE_EXCEPTION(ClassName) class ClassName: std::runtime_error {\ +public: ClassName(const std::string &message) : std::runtime_error(message) {}\ +}; + +namespace parser { + +DEFINE_EXCEPTION(end_of_file); + +class compile_error + :public std::runtime_error +{ +public: + compile_error(unsigned int line, const std::string &message) noexcept + : std::runtime_error(make_string("compile error at line ", line, ": ", message)) { + + } +}; + +} // namespace parser diff --git a/src/main.cpp b/src/main.cpp index 7b2591b..17d49d9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,20 +1,13 @@ -#include -#include -#include +#include #include -#include +#include +#include "parser.h" + +using namespace std; -int main(){ - std::fstream instream("helloworld.fpp"); - if(!instream.is_open()){ - return 1; //Can't open file +int main(int argc, char** argv) { + for(int i = 1; i < argc; ++i) { + parser::parser(std::ifstream(argv[i])).parse(); } - std::string code; - char c; - /*while(!instream.eof()){ - instream >> c; - code.push_back(c); - }*/ - //std::cout << code; return 0; } \ No newline at end of file diff --git a/src/parser.cpp b/src/parser.cpp index 8a2d2f1..6692953 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1,23 +1,135 @@ #include "parser.h" +#include "string_util.hpp" +#include "character_util.hpp" +#include -namespace parser{ - void Parser::parse(){ - std::string lastPattern; - int i = 0; - for (int i = 0; i < code.length(); i++){ - char ch = code[i]; - if (ch == ' ' || ch == '\r' || ch == '\n'){ - if(!lastPattern.empty()){ - //Throw error of invalid keyword +using namespace parser; + +namespace parser { + char parser::file_scanning_state::get_current_character() noexcept { + return currentCharacter; + } + + char parser::file_scanning_state::get_next_character() { + if(in.eof()) { + throw end_of_file("Read failed: end of stream."); + } + currentCharacter = in.get(); + return currentCharacter; + } + + bool parser::file_scanning_state::eof() noexcept {return in.eof();} + + void parser::scan_tokens() { + unsigned int line = 1; + + auto &skip_blanks = [&]() -> unsigned int { + unsigned int result = 0; + char c = fileScanningState.get_current_character(); + while(is_blank(c)) { + ++result; + if(c == '\n') { + ++line; } - lastPattern = ""; - return; + c = fileScanningState.get_next_character(); + } + return result; + }; + + + auto &read_name = [&]() -> std::string { + std::string result = ""; + char c = fileScanningState.get_current_character(); + if(is_letter(c) || c == '_') { + result += c; + c = fileScanningState.get_next_character(); } - if ((!lastPattern.empty())&&((std::string)"function").substr(0,lastPattern.length()-1)==lastPattern){ - lastPattern.push_back(ch); - }else{ - //Throw error of invalid keyword + else { + throw std::runtime_error("Is not reading a name."); + } + while(is_letter(c) || c == '_' || is_number_character(c)) { + result += c; + c = fileScanningState.get_next_character(); + } + return result; + }; + + try { + fileScanningState.get_next_character(); + while(!fileScanningState.eof()) { + skip_blanks(); + char c = fileScanningState.get_current_character(); + if(is_letter(c) || c == '_') { + auto name = read_name(); + if(name == "func") { + parsed_tokens.push_back(token_type::function); + } + else { + parsed_tokens.push_back(token_type::name); + } + continue; + } + else { + switch(c) { + case '[': + parsed_tokens.push_back(token_type::open_square_bracket); + break; + case ']': + parsed_tokens.push_back(token_type::close_square_bracket); + break; + case '(': + parsed_tokens.push_back(token_type::open_bracket); + break; + case ')': + parsed_tokens.push_back(token_type::close_bracket); + break; + case '{': + parsed_tokens.push_back(token_type::open_brace); + break; + case '}': + parsed_tokens.push_back(token_type::close_brace); + break; + default: + throw compile_error(line, make_string("Unexpected character \'", c, "\'.")); + } + } + c = fileScanningState.get_next_character(); + } + } + catch (std::exception &e) { + std::cerr << "[error] " << e.what() << std::endl; + } + } + + void parser::parse() { + scan_tokens(); + for(auto &token : parsed_tokens) { + switch(token.type) { + case token_type::function: + std::cout << "function "; + break; + case token_type::open_bracket: + std::cout << "( "; + break; + case token_type::close_bracket: + std::cout << ") "; + break; + case token_type::open_square_bracket: + std::cout << "[ "; + break; + case token_type::close_square_bracket: + std::cout << "] "; + break; + case token_type::open_brace: + std::cout << "{ "; + break; + case token_type::close_brace: + std::cout << "} "; + break; + case token_type::name: + std::cout << "name "; } } + std::cout << std::flush; } } // namespace parser \ No newline at end of file diff --git a/src/parser.h b/src/parser.h index a71b508..ce2bd9e 100644 --- a/src/parser.h +++ b/src/parser.h @@ -1,17 +1,54 @@ -#include +#pragma once +#include +#include +#include #include +#include "exceptions.hpp" namespace parser { - class Parser{ - private: + class parser { protected: - std::string code; - int readmode; + private: + std::istream ∈ + + class file_scanning_state { + private: + std::istream ∈ + char currentCharacter = 0; + public: + file_scanning_state(std::istream &in) noexcept: in(in) {} + char get_current_character() noexcept; + char get_next_character(); + bool eof() noexcept; + }fileScanningState; + + enum class token_type { + function, + open_bracket, + close_bracket, + open_square_bracket, + close_square_bracket, + open_brace, + close_brace, + name + }; + + struct extra_data {}; + + struct token { + token(token_type type) : type(type), extra_data(nullptr) {} + token(token_type type, const void * const extra_data) : type(type), extra_data(extra_data) {} + token_type type; + const void * const extra_data; + }; + + std::vector parsed_tokens; + + void scan_tokens(); public: - Parser(){} - Parser(std::string c) : code(c){} - virtual ~Parser(){} - virtual void parse(); + parser(std::istream &in) noexcept: in(in), fileScanningState(in) {} + ~parser() {}; + void parse(); }; } // namespace parser diff --git a/src/string_util.hpp b/src/string_util.hpp new file mode 100644 index 0000000..2aa5610 --- /dev/null +++ b/src/string_util.hpp @@ -0,0 +1,25 @@ +#pragma once +#include +#include + +namespace parser { + template + std::string make_string(Args... arguments) { + static std::stringstream buffer; + buffer.clear(); + buffer.str(""); + append_string_buffer(buffer, arguments...); + return buffer.str(); + } + template + void append_string_buffer(std::stringstream &buffer, T argument, Args... arguments) { + buffer << argument; + append_string_buffer(buffer, arguments...); + } + + template + void append_string_buffer(std::stringstream &buffer, T argument) { + buffer << argument; + } +} // namespace parser + diff --git a/test/helloworld.fpp b/test/helloworld.fpp index 94e9a1e..9a7e241 100644 --- a/test/helloworld.fpp +++ b/test/helloworld.fpp @@ -1,3 +1,3 @@ -func helloworld(){ +func helloworld() [] { say "a" } \ No newline at end of file