Bugs Fixed; Code Modified;
This commit is contained in:
parent
75f6dd87f1
commit
a5d808cabc
@ -3,4 +3,12 @@ project(syntaxParser)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
|
||||
add_executable(syntaxParser main.cpp)
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "/Ox")
|
||||
|
||||
include_directories(./include)
|
||||
|
||||
aux_source_directory(src SRC_FILES)
|
||||
|
||||
add_executable(LR1Generator LR1Generator.cpp ${SRC_FILES})
|
||||
|
||||
add_executable(syntaxParser LR1Generator.cpp ${SRC_FILES})
|
57
LR1Generator.cpp
Normal file
57
LR1Generator.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
#include <iostream>
|
||||
#include <ctime>
|
||||
|
||||
#include <SymbolTable.h>
|
||||
#include <GrammarResourcePool.h>
|
||||
|
||||
#include <AnalyseTableGenerator.h>
|
||||
|
||||
using std::vector;
|
||||
using std::wstring;
|
||||
|
||||
using std::wcout;
|
||||
using std::endl;
|
||||
|
||||
|
||||
#include <LR1Generator.h>
|
||||
#include <SyntaxParser.h>
|
||||
|
||||
|
||||
int main() {
|
||||
clock_t start,end;//定义clock_t变量
|
||||
start = clock(); //开始时间
|
||||
|
||||
const GrammarResourcePool *pool;
|
||||
|
||||
const AnalyseTableGenerator *atg;
|
||||
|
||||
|
||||
LR1Generator generator;
|
||||
|
||||
generator.getProductions();
|
||||
|
||||
generator.run();
|
||||
|
||||
generator.output(pool, atg);
|
||||
|
||||
//输出时间
|
||||
end = clock(); //结束时间
|
||||
double times = double(end-start)/CLOCKS_PER_SEC;
|
||||
wcout<<"LR1Generator Run time = "<< times <<"s MicroSeconds" << " = " << times * 1000 <<"ms" << endl;
|
||||
|
||||
start = clock(); //开始时间
|
||||
|
||||
SyntaxParser syntaxParser(pool, atg);
|
||||
|
||||
syntaxParser.getToken();
|
||||
|
||||
syntaxParser.parse();
|
||||
|
||||
//输出时间
|
||||
end = clock(); //结束时间
|
||||
times = double(end-start)/CLOCKS_PER_SEC;
|
||||
wcout<<"SyntaxParser Run time = "<<times<<"s MicroSeconds " << " = " << times * 1000 <<"ms" << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
7
SyntaxParser.cpp
Normal file
7
SyntaxParser.cpp
Normal file
@ -0,0 +1,7 @@
|
||||
//
|
||||
// Created by Administrator on 2021/4/30.
|
||||
//
|
||||
|
||||
int main() {
|
||||
|
||||
}
|
@ -1,7 +1,12 @@
|
||||
@struct_type -> "struct" "ID" "{" member_list "}" "EOF"
|
||||
member_list-> type_spec declarators ";"
|
||||
@struct_type -> "struct" "ID" "{" member_list "}" more_struct_type
|
||||
more_struct_type -> "EOF"
|
||||
more_struct_type -> ε
|
||||
|
||||
member_list -> type_spec declarators ";" member_list
|
||||
member_list -> ε
|
||||
|
||||
type_spec -> base_type_spec
|
||||
type_spec -> struct_type
|
||||
type_spec -> @struct_type
|
||||
base_type_spec -> floating_pt_type
|
||||
base_type_spec -> integer_type
|
||||
base_type_spec -> "char"
|
||||
@ -23,13 +28,13 @@ signed_int -> "int8"
|
||||
unsigned_int -> "unsigned" "short"
|
||||
unsigned_int -> "unsigned" "long"
|
||||
unsigned_int -> "unsigned" "long" "long"
|
||||
unsigned_int -> "unit16"
|
||||
unsigned_int -> "unit32"
|
||||
unsigned_int -> "unit64"
|
||||
unsigned_int -> "unit8"
|
||||
unsigned_int -> "uint16"
|
||||
unsigned_int -> "uint32"
|
||||
unsigned_int -> "uint64"
|
||||
unsigned_int -> "uint8"
|
||||
|
||||
declarators -> declarator more_declarators
|
||||
more_declarators -> "," declarator
|
||||
more_declarators -> "," declarator more_declarators
|
||||
more_declarators -> ε
|
||||
|
||||
declarator -> "ID" more_declarator
|
||||
@ -37,32 +42,48 @@ more_declarator -> exp_list
|
||||
more_declarator -> ε
|
||||
|
||||
exp_list -> "[" or_expr more_or_expr "]"
|
||||
more_or_expr -> "," or_expr
|
||||
more_or_expr -> "," or_expr more_or_expr
|
||||
more_or_expr -> ε
|
||||
|
||||
or_expr -> xor_expr more_xor_expr
|
||||
more_xor_expr -> "|" xor_expr more_xor_expr
|
||||
more_xor_expr -> ε
|
||||
|
||||
xor_expr -> and_expr more_and_expr
|
||||
more_and_expr -> "^" and_expr
|
||||
more_and_expr -> "^" and_expr more_and_expr
|
||||
more_and_expr -> ε
|
||||
|
||||
and_expr -> shift_expr more_shift_expr
|
||||
more_shift_expr -> "&" shift_expr
|
||||
more_shift_expr -> "&" shift_expr more_shift_expr
|
||||
more_shift_expr -> ε
|
||||
|
||||
shift_expr -> add_expr more_add_expr
|
||||
more_add_expr -> shift_sign add_expr
|
||||
more_add_expr -> shift_sign add_expr more_add_expr
|
||||
shift_sign -> ">>"
|
||||
shift_sign -> "<<"
|
||||
more_add_expr -> ε
|
||||
|
||||
add_expr -> multi_expr more_multi_expr
|
||||
more_multi_expr -> multi_sign multi_expr
|
||||
more_multi_expr -> multi_sign multi_expr more_multi_expr
|
||||
multi_sign -> "+"
|
||||
multi_sign -> "-"
|
||||
more_multi_expr -> ε
|
||||
|
||||
multi_expr -> unary_expr more_unary_expr
|
||||
more_unary_expr -> unary_sign unary_expr
|
||||
more_unary_expr -> ε
|
||||
more_unary_expr -> unary_sign unary_expr more_unary_expr
|
||||
unary_sign -> "*"
|
||||
unary_sign -> "/"
|
||||
unary_sign -> "%"
|
||||
more_unary_expr -> ε
|
||||
|
||||
unary_expr -> unary_sign_2 unary_declare
|
||||
unary_sign_2 -> "-"
|
||||
unary_sign_2 -> "+"
|
||||
unary_sign_2 -> "~"
|
||||
unary_sign_2 -> ε
|
||||
unary_declare -> "INTEGER"
|
||||
unary_declare -> "STRING"
|
||||
unary_declare -> "BOOLEAN"
|
||||
unary_declare -> BOOLEAN
|
||||
|
||||
BOOLEAN -> "TRUE"
|
||||
BOOLEAN -> "FALSE"
|
36
cmake-build-debug/tokenOut.txt
Normal file
36
cmake-build-debug/tokenOut.txt
Normal file
@ -0,0 +1,36 @@
|
||||
1 STRUCT(struct) ID(test) OPENING_BRACE({)
|
||||
2 FLOAT(float) ID(a1) SEMICOLON(;)
|
||||
3 DOUBLE(double) ID(a2) COMMA(,) ID(a3) COMMA(,) ID(a4) SEMICOLON(;)
|
||||
4 LONG(long) DOUBLE(double) ID(a5) SEMICOLON(;)
|
||||
5 STRUCT(struct) ID(warp_int) OPENING_BRACE({)
|
||||
6 INT8(int8) ID(i1) SEMICOLON(;)
|
||||
7 INT16(int16) ID(i2) SEMICOLON(;)
|
||||
8 INT32(int32) ID(i3) COMMA(,) ID(i4) SEMICOLON(;)
|
||||
9 INT64(int64) ID(i5) SEMICOLON(;)
|
||||
10 SHORT(short) ID(i6) SEMICOLON(;)
|
||||
11 LONG(long) ID(i7) SEMICOLON(;)
|
||||
12 LONG(long) LONG(long) ID(i8) SEMICOLON(;)
|
||||
13 CLOSING_BRACE(}) ID(int1) COMMA(,) ID(int2) SEMICOLON(;)
|
||||
14 STRUCT(struct) ID(warp_signInt) OPENING_BRACE({)
|
||||
15 UINT8(uint8) ID(s1) SEMICOLON(;)
|
||||
16 UINT16(uint16) ID(s2) SEMICOLON(;)
|
||||
17 UINT32(uint32) ID(s3) COMMA(,) ID(s4) SEMICOLON(;)
|
||||
18 UINT64(uint64) ID(s5) SEMICOLON(;)
|
||||
19 UNSIGNED(unsigned) SHORT(short) ID(s6) COMMA(,) ID(s7) SEMICOLON(;)
|
||||
20 UNSIGNED(unsigned) LONG(long) ID(s8) SEMICOLON(;)
|
||||
21 UNSIGNED(unsigned) LONG(long) LONG(long) ID(s9) SEMICOLON(;)
|
||||
22 CLOSING_BRACE(}) ID(sign1) COMMA(,) ID(SIGN2) SEMICOLON(;)
|
||||
23 CHAR(char) ID(a_6) LEFT_BRACKET([) STRING("compile") PLUS(+) STRING("studying") COMMA(,) STRING("\40") COMMA(,) STRING("abs\b\t\n\f\r\"\\abs") RIGHT_BRACKET(]) SEMICOLON(;)
|
||||
24 BOOLEAN(boolean) ID(a_bool_7) LEFT_BRACKET([) INTEGER(10) INSERT(^) INTEGER(2) COMMA(,) INTEGER(1) AND(&) INTEGER(2) AND(&) INTEGER(3) COMMA(,) TRUE(TRUE) DELIMITER(|) FALSE(FALSE) COMMA(,) TILDE(~) FALSE(FALSE) DELIMITER(|) TILDE(~) TRUE(TRUE) RIGHT_BRACKET(]) SEMICOLON(;)
|
||||
25 LONG(long) ID(a8) LEFT_BRACKET([) INTEGER(1024) RIGHT_SHIFT(>>) INTEGER(10) COMMA(,) INTEGER(0) LEFT_SHIFT(<<) INTEGER(10) COMMA(,) INTEGER(100) MULT(*) INTEGER(2) SLASH(/) INTEGER(10) PERCENT(%) INTEGER(2) COMMA(,) INTEGER(100) PLUS(+) INTEGER(21) SUB(-) INTEGER(19) RIGHT_BRACKET(]) SEMICOLON(;)
|
||||
26 BOOLEAN(boolean) ID(a9) LEFT_BRACKET([) INTEGER(10) INSERT(^) INTEGER(2) AND(&) INTEGER(3) DELIMITER(|) SUB(-) INTEGER(1) RIGHT_SHIFT(>>) INTEGER(10) AND(&) INTEGER(100) LEFT_SHIFT(<<) SUB(-) INTEGER(10) SUB(-) INTEGER(10) PLUS(+) INTEGER(100) MULT(*) INTEGER(2) SLASH(/) INTEGER(10) PERCENT(%) INTEGER(2) RIGHT_BRACKET(]) SEMICOLON(;)
|
||||
27 STRUCT(struct) ID(warp_1) OPENING_BRACE({)
|
||||
28 FLOAT(float) ID(w1) SEMICOLON(;)
|
||||
29 LONG(long) ID(w2) SEMICOLON(;)
|
||||
30 STRUCT(struct) ID(warp_2) OPENING_BRACE({)
|
||||
31 BOOLEAN(boolean) ID(w3) LEFT_BRACKET([) INTEGER(111) AND(&) INTEGER(2) RIGHT_BRACKET(]) SEMICOLON(;)
|
||||
32 CHAR(char) ID(w4) LEFT_BRACKET([) STRING("\40\b\t\n\f\r\"\\\40") RIGHT_BRACKET(]) SEMICOLON(;)
|
||||
33 CLOSING_BRACE(}) ID(w5) COMMA(,) ID(w6) SEMICOLON(;)
|
||||
34 CLOSING_BRACE(}) ID(w7) COMMA(,) ID(w8) SEMICOLON(;)
|
||||
35 CLOSING_BRACE(})
|
||||
36 EOF()
|
73
include/AnalyseTableGenerator.h
Normal file
73
include/AnalyseTableGenerator.h
Normal file
@ -0,0 +1,73 @@
|
||||
//
|
||||
// Created by Administrator on 2021/4/30.
|
||||
//
|
||||
|
||||
#ifndef SYNTAXPARSER_ANALYSETABLEGENERATOR_H
|
||||
#define SYNTAXPARSER_ANALYSETABLEGENERATOR_H
|
||||
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
|
||||
#include <GrammarResourcePool.h>
|
||||
#include <ItemCollectionManager.h>
|
||||
|
||||
|
||||
using Action = enum {
|
||||
MOVE, REDUCE, ACC, STEP_GOTO
|
||||
};
|
||||
|
||||
|
||||
class AnalyseTableGenerator {
|
||||
|
||||
struct Step {
|
||||
|
||||
const Action action;
|
||||
union Target{
|
||||
int index;
|
||||
const Production *production;
|
||||
} target{};
|
||||
|
||||
Step(Action action, int index) : action(action), target(Target{index}){}
|
||||
Step(Action action, const Production *p_pdt) : action(action) {
|
||||
target.production = p_pdt;
|
||||
}
|
||||
};
|
||||
|
||||
std::map<size_t, Step *> ACTION;
|
||||
|
||||
std::map<size_t, Step *> GOTO;
|
||||
|
||||
const ItemCollectionManager *icm;
|
||||
|
||||
const GrammarResourcePool *pool;
|
||||
|
||||
template <class T>
|
||||
inline void hash_combine(std::size_t& seed, const T& v) const
|
||||
{
|
||||
std::hash<T> hasher;
|
||||
seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
|
||||
}
|
||||
|
||||
void add_action(int index, int terminator_symbol, Action action, const Production *target_pdt);
|
||||
|
||||
void add_action(int index, int terminator_symbol, Action action, int target_index);
|
||||
|
||||
void add_goto(int index, int non_terminator_symbol, int target_index);
|
||||
|
||||
public:
|
||||
|
||||
explicit AnalyseTableGenerator(const GrammarResourcePool *p_pool, const ItemCollectionManager *p_icm)
|
||||
:pool(p_pool) , icm(p_icm) {}
|
||||
|
||||
void generate();
|
||||
|
||||
const Step *findActionStep(int index, int terminator_symbol) const;
|
||||
|
||||
const Step *findGotoStep(int index, int non_terminator_symbol) const;
|
||||
|
||||
void print() const;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif //SYNTAXPARSER_ANALYSETABLEGENERATOR_H
|
93
include/GrammarResourcePool.h
Normal file
93
include/GrammarResourcePool.h
Normal file
@ -0,0 +1,93 @@
|
||||
//
|
||||
// Created by Administrator on 2021/4/30.
|
||||
//
|
||||
|
||||
#ifndef SYNTAXPARSER_GRAMMARRESOURCEPOOL_H
|
||||
#define SYNTAXPARSER_GRAMMARRESOURCEPOOL_H
|
||||
|
||||
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
#include <SymbolTable.h>
|
||||
#include <Production.h>
|
||||
|
||||
// 语法资源池
|
||||
class GrammarResourcePool {
|
||||
|
||||
int pdt_index = 0;
|
||||
|
||||
// 符号表
|
||||
SymbolTable symbolTable;
|
||||
|
||||
// 产生式
|
||||
std::vector<const Production *> productions;
|
||||
|
||||
// FIRST结果存储表
|
||||
std::map<int, const std::set<int> *> firsts;
|
||||
|
||||
// FOLLOW结果存储表
|
||||
std::map<int, std::set<int> *> follows;
|
||||
|
||||
// 去掉首尾空格
|
||||
static std::wstring& trim(std::wstring &&str) {
|
||||
if (str.empty()) {
|
||||
return str;
|
||||
}
|
||||
|
||||
str.erase(0,str.find_first_not_of(' '));
|
||||
str.erase(str.find_last_not_of(' ') + 1);
|
||||
return str;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
const std::set<int > *FIRST(const std::vector<int> &symbols, int start_index);
|
||||
|
||||
const std::set<int>* FIRST(int symbol);
|
||||
|
||||
const std::set<int> *FOLLOW(int symbol);
|
||||
|
||||
void FOLLOW();
|
||||
|
||||
std::set<int>* get_follow_set(int symbol);
|
||||
|
||||
|
||||
void print_symbols(const std::set<int> &symbols_index);
|
||||
|
||||
void parse_production_string_line(const std::wstring &temp_line);
|
||||
|
||||
[[nodiscard]] const std::vector<const Production *> &get_productions() const {
|
||||
return productions;
|
||||
}
|
||||
|
||||
[[nodiscard]] const Symbol *getSymbol(int symbol_index) const {
|
||||
return symbolTable.getSymbol(symbol_index);
|
||||
}
|
||||
|
||||
[[nodiscard]] const Symbol *getStartSymbol() const {
|
||||
return symbolTable.getStartSymbol();
|
||||
}
|
||||
|
||||
int addSymbol(const std::wstring &name, bool terminator) {
|
||||
return symbolTable.addSymbol(name, terminator);
|
||||
}
|
||||
|
||||
const Production *addProduction(int left, std::initializer_list<int> right);
|
||||
|
||||
[[nodiscard]] const std::vector<const Symbol *> &getAllSymbols() const {
|
||||
return symbolTable.getAllSymbols();
|
||||
}
|
||||
|
||||
void modifySymbol(int index, const std::wstring &name, bool terminator, bool start) {
|
||||
symbolTable.modifySymbol(index, name, terminator, start);
|
||||
}
|
||||
|
||||
[[nodiscard]] int getSymbolIndex(const std::wstring &name) const {
|
||||
return symbolTable.getSymbolIndex(name);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif //SYNTAXPARSER_GRAMMARRESOURCEPOOL_H
|
53
include/Item.h
Normal file
53
include/Item.h
Normal file
@ -0,0 +1,53 @@
|
||||
//
|
||||
// Created by Administrator on 2021/4/30.
|
||||
//
|
||||
|
||||
#ifndef SYNTAXPARSER_ITEM_H
|
||||
#define SYNTAXPARSER_ITEM_H
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <Production.h>
|
||||
|
||||
// 项
|
||||
class Item{
|
||||
// 对应的产生式
|
||||
const Production* const production;
|
||||
|
||||
// 点的位置
|
||||
int dot_index = 0;
|
||||
|
||||
const int terminator = 0;
|
||||
|
||||
public:
|
||||
|
||||
const bool generated = false;
|
||||
|
||||
explicit Item(const Production *p_pdt, int m_terminator, bool m_generated = false)
|
||||
: production(p_pdt), terminator(m_terminator), generated(m_generated) {}
|
||||
|
||||
void set_dot_index(int m_dot_index);
|
||||
|
||||
[[nodiscard]] int get_dot_index() const {
|
||||
return dot_index;
|
||||
}
|
||||
|
||||
[[nodiscard]] size_t get_right_size() {
|
||||
return production->right.size();
|
||||
}
|
||||
|
||||
int get_dot_next_symbol() const;
|
||||
|
||||
int get_dot_next_i_symbol(int i) const;
|
||||
|
||||
[[nodiscard]] int get_terminator() const {
|
||||
return terminator;
|
||||
}
|
||||
|
||||
[[nodiscard]] const Production *get_production() const {
|
||||
return production;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif //SYNTAXPARSER_ITEM_H
|
64
include/ItemCollection.h
Normal file
64
include/ItemCollection.h
Normal file
@ -0,0 +1,64 @@
|
||||
//
|
||||
// Created by Administrator on 2021/4/30.
|
||||
//
|
||||
|
||||
#ifndef SYNTAXPARSER_ITEMCOLLECTION_H
|
||||
#define SYNTAXPARSER_ITEMCOLLECTION_H
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
|
||||
#include <Item.h>
|
||||
#include <GrammarResourcePool.h>
|
||||
|
||||
class ItemCollectionManager;
|
||||
|
||||
class ItemCollection{
|
||||
|
||||
int index = 0;
|
||||
|
||||
std::map<size_t, Item *> items;
|
||||
|
||||
std::vector<Item *> cache;
|
||||
|
||||
GrammarResourcePool *pool;
|
||||
|
||||
friend ItemCollectionManager;
|
||||
|
||||
template <class T>
|
||||
inline void hash_combine(std::size_t& seed, const T& v) const
|
||||
{
|
||||
std::hash<T> hasher;
|
||||
seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
|
||||
}
|
||||
|
||||
static bool compare_item_ptr(const Item* lhs, const Item* rhs);
|
||||
|
||||
public:
|
||||
|
||||
explicit ItemCollection(GrammarResourcePool *pool) : pool(pool) {
|
||||
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::vector<Item *> &getItems() const {
|
||||
return cache;
|
||||
}
|
||||
|
||||
[[nodiscard]] int getIndex() const {
|
||||
return index;
|
||||
}
|
||||
|
||||
|
||||
bool addItem(const Production *p_pdt, int dot_index, int terminator, bool generated = false);
|
||||
|
||||
void CLOSURE();
|
||||
|
||||
void print(std::wofstream &output) const;
|
||||
|
||||
[[nodiscard]] size_t getHash() const;
|
||||
};
|
||||
|
||||
#endif //SYNTAXPARSER_ITEMCOLLECTION_H
|
73
include/ItemCollectionManager.h
Normal file
73
include/ItemCollectionManager.h
Normal file
@ -0,0 +1,73 @@
|
||||
//
|
||||
// Created by Administrator on 2021/4/30.
|
||||
//
|
||||
|
||||
#ifndef SYNTAXPARSER_ITEMCOLLECTIONMANAGER_H
|
||||
#define SYNTAXPARSER_ITEMCOLLECTIONMANAGER_H
|
||||
|
||||
#include <fstream>
|
||||
#include <codecvt>
|
||||
|
||||
#include <ItemCollection.h>
|
||||
|
||||
|
||||
class ItemCollectionManager{
|
||||
|
||||
std::wofstream output;
|
||||
|
||||
int index = 0;
|
||||
|
||||
std::map<size_t, ItemCollection *> ic_map;
|
||||
|
||||
std::map<size_t, ItemCollection *> ic_content_map;
|
||||
|
||||
std::vector<const ItemCollection *> ics;
|
||||
|
||||
GrammarResourcePool *pool;
|
||||
|
||||
const Production *start_pdt{};
|
||||
|
||||
template <class T>
|
||||
inline void hash_combine(std::size_t& seed, const T& v) const
|
||||
{
|
||||
std::hash<T> hasher;
|
||||
seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
explicit ItemCollectionManager(GrammarResourcePool *resource_pool) :
|
||||
pool(resource_pool),
|
||||
output("LR1Automata.txt", std::ios::binary) {
|
||||
|
||||
auto* codeCvtToUTF8= new std::codecvt_utf8<wchar_t>;
|
||||
output.imbue(std::locale(output.getloc(), codeCvtToUTF8));
|
||||
|
||||
}
|
||||
|
||||
~ItemCollectionManager(){
|
||||
output.close();
|
||||
}
|
||||
|
||||
void buildItems();
|
||||
|
||||
[[nodiscard]] const Production *getStartProduction() const {
|
||||
return start_pdt;
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::vector<const ItemCollection *> &getItemCollections() const{
|
||||
return ics;
|
||||
}
|
||||
|
||||
ItemCollection *getItemCollectionByHash(size_t hash);
|
||||
|
||||
bool addItemCollection(int idx, int symbol, ItemCollection *p_ic);
|
||||
|
||||
[[nodiscard]] const ItemCollection* getGOTO(int idx, int symbol) const;
|
||||
|
||||
bool GOTO(const ItemCollection *p_ic, int symbol);
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif //SYNTAXPARSER_ITEMCOLLECTIONMANAGER_H
|
60
include/LR1Generator.h
Normal file
60
include/LR1Generator.h
Normal file
@ -0,0 +1,60 @@
|
||||
//
|
||||
// Created by Administrator on 2021/4/30.
|
||||
//
|
||||
|
||||
#ifndef SYNTAXPARSER_LR1GENERATOR_H
|
||||
#define SYNTAXPARSER_LR1GENERATOR_H
|
||||
|
||||
#include <codecvt>
|
||||
|
||||
#include <GrammarResourcePool.h>
|
||||
#include <ItemCollectionManager.h>
|
||||
#include <AnalyseTableGenerator.h>
|
||||
|
||||
|
||||
class LR1Generator{
|
||||
|
||||
// 文件输入
|
||||
std::wifstream input;
|
||||
|
||||
GrammarResourcePool *pool;
|
||||
|
||||
ItemCollectionManager *icm;
|
||||
|
||||
AnalyseTableGenerator *atg;
|
||||
|
||||
public:
|
||||
|
||||
LR1Generator(): input("syntaxInput.txt", std::ios::binary),
|
||||
pool(new GrammarResourcePool()),
|
||||
icm(new ItemCollectionManager(pool)),
|
||||
atg(new AnalyseTableGenerator(pool, icm)){
|
||||
|
||||
auto* codeCvtToUTF8= new std::codecvt_utf8<wchar_t>;
|
||||
|
||||
input.imbue(std::locale(input.getloc(), codeCvtToUTF8));
|
||||
}
|
||||
|
||||
~LR1Generator() {
|
||||
input.close();
|
||||
}
|
||||
|
||||
void run() {
|
||||
pool->FOLLOW();
|
||||
icm->buildItems();
|
||||
atg->generate();
|
||||
atg->print();
|
||||
}
|
||||
|
||||
// 得到所有的产生式
|
||||
void getProductions();
|
||||
|
||||
void output(const GrammarResourcePool *&m_pool, const AnalyseTableGenerator *&m_atg) {
|
||||
m_pool = this->pool;
|
||||
m_atg = this->atg;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif //SYNTAXPARSER_LR1GENERATOR_H
|
22
include/Production.h
Normal file
22
include/Production.h
Normal file
@ -0,0 +1,22 @@
|
||||
//
|
||||
// Created by Administrator on 2021/4/30.
|
||||
//
|
||||
|
||||
#ifndef SYNTAXPARSER_PRODUCTION_H
|
||||
#define SYNTAXPARSER_PRODUCTION_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
// ²úÉúʽ
|
||||
struct Production {
|
||||
|
||||
const int index;
|
||||
const int left;
|
||||
const std::vector<int> right;
|
||||
|
||||
Production(int index, int left, std::vector<int> right): index(index), left(left), right(std::move(right)) {}
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif //SYNTAXPARSER_PRODUCTION_H
|
27
include/Symbol.h
Normal file
27
include/Symbol.h
Normal file
@ -0,0 +1,27 @@
|
||||
//
|
||||
// Created by Administrator on 2021/4/30.
|
||||
//
|
||||
|
||||
#ifndef SYNTAXPARSER_SYMBOL_H
|
||||
#define SYNTAXPARSER_SYMBOL_H
|
||||
|
||||
#include <string>
|
||||
|
||||
struct Symbol {
|
||||
|
||||
const int index;
|
||||
std::wstring name;
|
||||
bool terminator;
|
||||
bool start;
|
||||
|
||||
Symbol(int index, std::wstring name, bool terminator, bool start):
|
||||
index(index),
|
||||
name(std::move(name)),
|
||||
terminator(terminator),
|
||||
start(start)
|
||||
{}
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif //SYNTAXPARSER_SYMBOL_H
|
47
include/SymbolTable.h
Normal file
47
include/SymbolTable.h
Normal file
@ -0,0 +1,47 @@
|
||||
//
|
||||
// Created by Administrator on 2021/4/30.
|
||||
//
|
||||
|
||||
#ifndef SYNTAXPARSER_SYMBOLTABLE_H
|
||||
#define SYNTAXPARSER_SYMBOLTABLE_H
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <Symbol.h>
|
||||
|
||||
|
||||
class SymbolTable {
|
||||
|
||||
int index = 1;
|
||||
|
||||
std::map<std::wstring, Symbol *> table;
|
||||
|
||||
std::map<int, Symbol *> cache;
|
||||
|
||||
std::vector<const Symbol *> line;
|
||||
|
||||
public:
|
||||
|
||||
SymbolTable();
|
||||
|
||||
[[nodiscard]] const std::vector<const Symbol *> &getAllSymbols() const {
|
||||
return line;
|
||||
}
|
||||
|
||||
int addSymbol(const std::wstring& name, bool terminator);
|
||||
|
||||
[[nodiscard]] const Symbol *getSymbol(int symbol_index) const;
|
||||
|
||||
[[nodiscard]] int getSymbolIndex(const std::wstring &name) const;
|
||||
|
||||
void modifySymbol(int idx, const std::wstring &name, bool terminator, bool start);
|
||||
|
||||
[[nodiscard]] const Symbol *getStartSymbol() const;
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif //SYNTAXPARSER_SYMBOLTABLE_H
|
78
include/SyntaxParser.h
Normal file
78
include/SyntaxParser.h
Normal file
@ -0,0 +1,78 @@
|
||||
//
|
||||
// Created by Administrator on 2021/4/30.
|
||||
//
|
||||
|
||||
#ifndef SYNTAXPARSER_SYNTAXPARSER_H
|
||||
#define SYNTAXPARSER_SYNTAXPARSER_H
|
||||
|
||||
#include <queue>
|
||||
#include <stack>
|
||||
#include <regex>
|
||||
#include <codecvt>
|
||||
|
||||
#include <GrammarResourcePool.h>
|
||||
#include <AnalyseTableGenerator.h>
|
||||
|
||||
|
||||
|
||||
class SyntaxParser {
|
||||
|
||||
// 文件输入
|
||||
std::wifstream input;
|
||||
|
||||
std::wofstream output;
|
||||
|
||||
const GrammarResourcePool *pool;
|
||||
|
||||
const AnalyseTableGenerator *atg;
|
||||
|
||||
std::queue<int> tokens_queue;
|
||||
|
||||
std::stack<int> analyse_stack;
|
||||
|
||||
std::stack<int> status_stack;
|
||||
|
||||
std::vector<size_t> lines_index;
|
||||
|
||||
std::wstringstream string_buffer;
|
||||
|
||||
size_t now_line = 1;
|
||||
|
||||
static std::vector<std::wstring> ws_split(const std::wstring& in, const std::wstring& delim);
|
||||
|
||||
static std::pair<std::wstring, std::wstring> get_token_info(const std::wstring &token);
|
||||
|
||||
public:
|
||||
|
||||
SyntaxParser(const GrammarResourcePool *pool, const AnalyseTableGenerator *atg):
|
||||
input("tokenOut.txt", std::ios::binary),
|
||||
pool(pool),
|
||||
atg(atg),
|
||||
output("SyntaxOut.txt", std::ios::binary){
|
||||
|
||||
auto* codeCvtToUTF8= new std::codecvt_utf8<wchar_t>;
|
||||
input.imbue(std::locale(input.getloc(), codeCvtToUTF8));
|
||||
output.imbue(std::locale(output.getloc(), codeCvtToUTF8));
|
||||
}
|
||||
|
||||
~SyntaxParser() {
|
||||
output.close();
|
||||
}
|
||||
|
||||
// 得到所有的产生式
|
||||
void getToken();
|
||||
|
||||
void printSymbol(int symbol_index);
|
||||
|
||||
void printProduction(const Production *p_pdt);
|
||||
|
||||
// 自底向上语法分析
|
||||
void parse();
|
||||
|
||||
void printError();
|
||||
|
||||
void printDone();
|
||||
};
|
||||
|
||||
|
||||
#endif //SYNTAXPARSER_SYNTAXPARSER_H
|
194
src/AnalyseTableGenerator.cpp
Normal file
194
src/AnalyseTableGenerator.cpp
Normal file
@ -0,0 +1,194 @@
|
||||
//
|
||||
// Created by Administrator on 2021/4/30.
|
||||
//
|
||||
|
||||
#include "AnalyseTableGenerator.h"
|
||||
|
||||
void AnalyseTableGenerator::add_action(int index, int terminator_symbol, Action action, const Production *target_pdt) {
|
||||
size_t seed = 0;
|
||||
hash_combine(seed, index);
|
||||
hash_combine(seed, terminator_symbol);
|
||||
|
||||
auto it = ACTION.find(seed);
|
||||
if(it == ACTION.end()) {
|
||||
auto step = new Step(action, target_pdt);
|
||||
ACTION.insert(std::pair<size_t, Step *>(seed, step));
|
||||
} else {
|
||||
if(it->second->action != action || it->second->target.production != target_pdt)
|
||||
throw std::runtime_error("Conflict Occurred, Syntax NOT LR(1)");
|
||||
}
|
||||
}
|
||||
|
||||
void AnalyseTableGenerator::add_action(int index, int terminator_symbol, Action action, int target_index) {
|
||||
size_t seed = 0;
|
||||
hash_combine(seed, index);
|
||||
hash_combine(seed, terminator_symbol);
|
||||
|
||||
auto it = ACTION.find(seed);
|
||||
if(it == ACTION.end()) {
|
||||
auto step = new Step(action, target_index);
|
||||
ACTION.insert(std::pair<size_t, Step *>(seed, step));
|
||||
} else {
|
||||
if(it->second->action != action || it->second->target.index != target_index)
|
||||
throw std::runtime_error("Conflict Occurred, Syntax NOT LR(1)");
|
||||
}
|
||||
}
|
||||
|
||||
void AnalyseTableGenerator::add_goto(int index, int non_terminator_symbol, int target_index) {
|
||||
size_t seed = 0;
|
||||
hash_combine(seed, index);
|
||||
hash_combine(seed, non_terminator_symbol);
|
||||
|
||||
auto it = GOTO.find(seed);
|
||||
if(it == GOTO.end()) {
|
||||
auto step = new Step(STEP_GOTO, target_index);
|
||||
GOTO.insert(std::pair<size_t, Step *>(seed, step));
|
||||
} else {
|
||||
if(it->second->target.index != target_index)
|
||||
throw std::runtime_error("Conflict Occurred, Syntax NOT LR(1)");
|
||||
}
|
||||
}
|
||||
|
||||
void AnalyseTableGenerator::generate() {
|
||||
const auto &ics = icm->getItemCollections();
|
||||
for(const auto *ic : ics) {
|
||||
for(const auto *item : ic->getItems()) {
|
||||
if(item->get_production() == icm->getStartProduction()
|
||||
&& item->get_dot_next_symbol() == 0
|
||||
&& item->get_terminator() == -1) {
|
||||
this->add_action(ic->getIndex(), -1, ACC, 0);
|
||||
}
|
||||
int next_symbol = item->get_dot_next_symbol();
|
||||
if(next_symbol != 0) {
|
||||
const auto *p_ic = icm->getGOTO(ic->getIndex(), next_symbol);
|
||||
if(pool->getSymbol(next_symbol)->terminator) {
|
||||
if (p_ic != nullptr) {
|
||||
this->add_action(ic->getIndex(), next_symbol, MOVE, p_ic->getIndex());
|
||||
}
|
||||
} else {
|
||||
if (p_ic != nullptr) {
|
||||
this->add_goto(ic->getIndex(), next_symbol, p_ic->getIndex());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(pool->getSymbol(next_symbol)->terminator) {
|
||||
if (item->get_production()->left != pool->getStartSymbol()->index) {
|
||||
this->add_action(ic->getIndex(), item->get_terminator(), REDUCE, item->get_production());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const AnalyseTableGenerator::Step *AnalyseTableGenerator::findActionStep(int index, int terminator_symbol) const {
|
||||
size_t seed = 0;
|
||||
hash_combine(seed, index);
|
||||
hash_combine(seed, terminator_symbol);
|
||||
|
||||
auto it = ACTION.find(seed);
|
||||
if(it != ACTION.end()) {
|
||||
return it->second;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const AnalyseTableGenerator::Step *AnalyseTableGenerator::findGotoStep(int index, int non_terminator_symbol) const {
|
||||
size_t seed = 0;
|
||||
hash_combine(seed, index);
|
||||
hash_combine(seed, non_terminator_symbol);
|
||||
|
||||
auto it = GOTO.find(seed);
|
||||
if (it != GOTO.end()) {
|
||||
return it->second;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void AnalyseTableGenerator::print() const {
|
||||
|
||||
std::wofstream output("tables.txt");
|
||||
|
||||
size_t space = 4;
|
||||
|
||||
output << L"ACTION" << std::endl;
|
||||
std::vector<int> symbols;
|
||||
|
||||
|
||||
for(const auto *symbol : pool->getAllSymbols()) {
|
||||
if(symbol->index == 0) continue;
|
||||
if(symbol->terminator) {
|
||||
space = std::max(space, symbol->name.size() + 2);
|
||||
symbols.push_back(symbol->index);
|
||||
}
|
||||
}
|
||||
|
||||
output << std::left << std::setw(space) << " ";
|
||||
for(const auto symbol_index : symbols) {
|
||||
output << std::left << std::setw(space) << pool->getSymbol(symbol_index)->name;
|
||||
}
|
||||
|
||||
output << std::endl;
|
||||
|
||||
for(int i = 0; i < icm->getItemCollections().size(); i++){
|
||||
output << std::left << std::setw(space) << i;
|
||||
for(int symbol : symbols) {
|
||||
auto p_step = this->findActionStep(i, symbol);
|
||||
if(p_step == nullptr) {
|
||||
output << std::left << std::setw(space) << " ";
|
||||
} else {
|
||||
if(p_step->action == MOVE)
|
||||
output << std::left << std::setw(space)
|
||||
<< std::wstring(L"s") + std::to_wstring(p_step->target.index);
|
||||
else if(p_step->action == ACC)
|
||||
output << std::left << std::setw(space) << L"acc";
|
||||
else if(p_step->action == REDUCE)
|
||||
output << std::left << std::setw(space)
|
||||
<< L"r" + std::to_wstring(p_step->target.production->index);
|
||||
}
|
||||
}
|
||||
output << std::endl;
|
||||
|
||||
}
|
||||
|
||||
output << std::endl;
|
||||
|
||||
space = 4;
|
||||
|
||||
output << "GOTO" << std::endl;
|
||||
symbols.clear();
|
||||
|
||||
for(const auto *symbol : pool->getAllSymbols()) {
|
||||
if(symbol->index == 0) continue;
|
||||
if(!symbol->terminator && !symbol->start) {
|
||||
space = std::max(space, symbol->name.size() + 2);
|
||||
symbols.push_back(symbol->index);
|
||||
}
|
||||
}
|
||||
|
||||
output << std::left << std::setw(space) << " ";
|
||||
for(const auto symbol_index : symbols) {
|
||||
output << std::left << std::setw(space) << pool->getSymbol(symbol_index)->name;
|
||||
}
|
||||
|
||||
output <<std::endl;
|
||||
|
||||
for(int k = 0; k < icm->getItemCollections().size(); k++) {
|
||||
output << std::left << std::setw(space) << k;
|
||||
for (int symbol : symbols) {
|
||||
auto p_step = this->findGotoStep(k, symbol);
|
||||
if(p_step == nullptr) {
|
||||
output << std::left << std::setw(space) << " ";
|
||||
} else {
|
||||
output << std::left << std::setw(space) << std::to_wstring(p_step->target.index);
|
||||
}
|
||||
}
|
||||
output << std::endl;
|
||||
}
|
||||
|
||||
output << std::endl << std::endl;
|
||||
|
||||
output.close();
|
||||
}
|
276
src/GrammarResourcePool.cpp
Normal file
276
src/GrammarResourcePool.cpp
Normal file
@ -0,0 +1,276 @@
|
||||
//
|
||||
// Created by Administrator on 2021/4/30.
|
||||
//
|
||||
|
||||
#include "GrammarResourcePool.h"
|
||||
|
||||
const std::set<int> *GrammarResourcePool::FIRST(const std::vector<int> &symbols, int start_index) {
|
||||
|
||||
// 生成集合
|
||||
auto *non_terminator_symbols = new std::set<int>();
|
||||
|
||||
for(int i = start_index; i < symbols.size(); i++) {
|
||||
|
||||
const auto p_non_term_set = FIRST(symbols[i]);
|
||||
|
||||
non_terminator_symbols->insert(p_non_term_set->begin(), p_non_term_set->end());
|
||||
|
||||
const auto sec_it = p_non_term_set->find(0);
|
||||
if(sec_it != p_non_term_set->end()) {
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return non_terminator_symbols;
|
||||
}
|
||||
|
||||
const std::set<int> *GrammarResourcePool::FIRST(int symbol) {
|
||||
|
||||
// 查找缓存
|
||||
const auto it = firsts.find(symbol);
|
||||
if(it != firsts.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
// 生成集合
|
||||
auto *non_terminator_symbols = new std::set<int>();
|
||||
|
||||
// 如果是终结符
|
||||
if(symbolTable.getSymbol(symbol)->terminator) {
|
||||
non_terminator_symbols->insert(symbol);
|
||||
} else {
|
||||
|
||||
bool production_found = false;
|
||||
|
||||
// 遍历每一产生式
|
||||
for (const auto &production : productions) {
|
||||
const Production *p_pdt = production;
|
||||
|
||||
if (p_pdt->left != symbol) continue;
|
||||
|
||||
production_found = true;
|
||||
|
||||
for (const auto &right_symbol : p_pdt->right) {
|
||||
|
||||
const auto p_non_term_set = FIRST(right_symbol);
|
||||
|
||||
non_terminator_symbols->insert(p_non_term_set->begin(), p_non_term_set->end());
|
||||
|
||||
const auto sec_it = p_non_term_set->find(0);
|
||||
|
||||
if(sec_it != p_non_term_set->end()) {
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (!production_found) non_terminator_symbols->insert(0);
|
||||
}
|
||||
|
||||
this->firsts.insert(std::pair<int, const std::set<int> *>(symbol, non_terminator_symbols));
|
||||
|
||||
return non_terminator_symbols;
|
||||
}
|
||||
|
||||
const std::set<int> *GrammarResourcePool::FOLLOW(int symbol) {
|
||||
if(follows.empty()) {
|
||||
FOLLOW();
|
||||
}
|
||||
|
||||
const auto it = follows.find(symbol);
|
||||
if(it != follows.end()) {
|
||||
return it->second;
|
||||
} else {
|
||||
throw std::runtime_error("symbol NOT Found");
|
||||
}
|
||||
}
|
||||
|
||||
void GrammarResourcePool::FOLLOW() {
|
||||
|
||||
for (const auto &symbol : symbolTable.getAllSymbols()) {
|
||||
if (!symbol->terminator) {
|
||||
if (symbol->start) {
|
||||
std::set<int> *non_terminator_symbols = get_follow_set(symbol->index);
|
||||
non_terminator_symbols->insert(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 指导没有新的符号被添加到任意FOLLOW集合
|
||||
bool ifAdded = true;
|
||||
|
||||
while(ifAdded) {
|
||||
|
||||
ifAdded = false;
|
||||
|
||||
|
||||
std::set<int> *non_terminator_symbols = nullptr;
|
||||
|
||||
|
||||
for (const auto &production : productions) {
|
||||
|
||||
const auto &right_symbols = production->right;
|
||||
|
||||
std::set<int> equal_left_non_terminators;
|
||||
|
||||
for (int i = 0; i < right_symbols.size() - 1; i++) {
|
||||
|
||||
// 非终结符
|
||||
if (!symbolTable.getSymbol(right_symbols[i])->terminator) {
|
||||
|
||||
const auto p_non_term_set = FIRST(right_symbols, i + 1);
|
||||
|
||||
// 获得FOLLOW集
|
||||
non_terminator_symbols = get_follow_set(right_symbols[i]);
|
||||
|
||||
const size_t set_size = non_terminator_symbols->size();
|
||||
|
||||
non_terminator_symbols->insert(p_non_term_set->begin(), p_non_term_set->end());
|
||||
|
||||
// 在集合中发现空字符
|
||||
if(non_terminator_symbols->find(0) != non_terminator_symbols->end()) {
|
||||
non_terminator_symbols->erase(0);
|
||||
equal_left_non_terminators.insert(right_symbols[i]);
|
||||
}
|
||||
|
||||
// 检查是否有新的终结符号被添加
|
||||
if(set_size < non_terminator_symbols->size()) {
|
||||
ifAdded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!right_symbols.empty()) {
|
||||
if (!symbolTable.getSymbol(right_symbols[right_symbols.size() - 1])->terminator) {
|
||||
equal_left_non_terminators.insert(right_symbols[right_symbols.size() - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
for(const auto symbol : equal_left_non_terminators) {
|
||||
// 获得左边非终结符的FOLLOW集
|
||||
const auto left_non_terminator_symbols = get_follow_set(production->left);
|
||||
// 获得FOLLOW集
|
||||
non_terminator_symbols = get_follow_set(symbol);
|
||||
|
||||
const size_t set_size = non_terminator_symbols->size();
|
||||
|
||||
non_terminator_symbols->insert(
|
||||
left_non_terminator_symbols->begin(),
|
||||
left_non_terminator_symbols->end());
|
||||
|
||||
if(non_terminator_symbols->find(0) != non_terminator_symbols->end()) {
|
||||
non_terminator_symbols->erase(0);
|
||||
}
|
||||
|
||||
// 检查是否有新的终结符号被添加
|
||||
if(set_size < non_terminator_symbols->size()) {
|
||||
ifAdded = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::set<int> *GrammarResourcePool::get_follow_set(int symbol) {
|
||||
|
||||
std::set<int> *non_terminator_symbols = nullptr;
|
||||
|
||||
// 查找缓存
|
||||
auto it = follows.find(symbol);
|
||||
if(it != follows.end()) {
|
||||
non_terminator_symbols = it->second;
|
||||
} else {
|
||||
non_terminator_symbols = new std::set<int>();
|
||||
this->follows.insert(std::pair<int, std::set<int> *>(symbol, non_terminator_symbols));
|
||||
}
|
||||
|
||||
return non_terminator_symbols;
|
||||
|
||||
}
|
||||
|
||||
void GrammarResourcePool::print_symbols(const std::set<int> &symbols_index) {
|
||||
std::wcout << L"{ ";
|
||||
for(const auto & symbol_index : symbols_index) {
|
||||
auto *p_sym = symbolTable.getSymbol(symbol_index);
|
||||
|
||||
if(p_sym->terminator) {
|
||||
if (p_sym->name == L"ε") {
|
||||
std::wcout << L" [Epsilon] ";
|
||||
}
|
||||
else std::wcout << L" \"" << p_sym->name << L"\" ";
|
||||
} else {
|
||||
std::wcout << L" " << p_sym->name << L" ";
|
||||
}
|
||||
|
||||
}
|
||||
std::wcout << L"}" << std::endl;
|
||||
}
|
||||
|
||||
void GrammarResourcePool::parse_production_string_line(const std::wstring &temp_line) {
|
||||
auto middle_index = temp_line.find(L"->", 0);
|
||||
|
||||
|
||||
if(middle_index == std::wstring::npos) {
|
||||
throw std::runtime_error("-> NOT FOUND");
|
||||
}
|
||||
|
||||
std::wstring front = trim(temp_line.substr(0, middle_index));
|
||||
int left = symbolTable.addSymbol(front, false);
|
||||
|
||||
std::wstring back = trim(temp_line.substr(middle_index + 2, temp_line.size() - middle_index - 2));
|
||||
|
||||
std::wstringstream terminator, non_terminator;
|
||||
std::vector<int> symbols;
|
||||
bool is_terminator = false;
|
||||
for(const auto &c : back) {
|
||||
if (c == L'\"') {
|
||||
if(is_terminator) {
|
||||
symbols.push_back(symbolTable.addSymbol(trim(terminator.str()), true));
|
||||
terminator.str(L"");
|
||||
terminator.clear();
|
||||
}
|
||||
is_terminator = !is_terminator;
|
||||
continue;
|
||||
}
|
||||
if(c == L' ' || c == L'\r') {
|
||||
std::wstring temp_symbol = trim(non_terminator.str());
|
||||
if(!temp_symbol.empty()) {
|
||||
symbols.push_back(symbolTable.addSymbol(trim(non_terminator.str()), false));
|
||||
non_terminator.str(L"");
|
||||
non_terminator.clear();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if(is_terminator) {
|
||||
terminator << c;
|
||||
} else {
|
||||
non_terminator << c;
|
||||
}
|
||||
}
|
||||
std::wstring temp_symbol = trim(non_terminator.str());
|
||||
if(!temp_symbol.empty()) {
|
||||
symbols.push_back(symbolTable.addSymbol(trim(non_terminator.str()), false));
|
||||
}
|
||||
|
||||
auto p_pdt = new Production(pdt_index++, left, symbols);
|
||||
|
||||
productions.push_back(p_pdt);
|
||||
}
|
||||
|
||||
const Production *GrammarResourcePool::addProduction(int left, std::initializer_list<int> right) {
|
||||
std::vector<int> right_vector;
|
||||
for(int symbol : right) {
|
||||
right_vector.push_back(symbol);
|
||||
}
|
||||
auto p_pdt = new Production(pdt_index++, left, right_vector);
|
||||
productions.push_back(p_pdt);
|
||||
return p_pdt;
|
||||
}
|
28
src/Item.cpp
Normal file
28
src/Item.cpp
Normal file
@ -0,0 +1,28 @@
|
||||
//
|
||||
// Created by Administrator on 2021/4/30.
|
||||
//
|
||||
|
||||
#include "Item.h"
|
||||
|
||||
void Item::set_dot_index(int m_dot_index) {
|
||||
if(m_dot_index > production->right.size()) {
|
||||
throw std::runtime_error("DOT_INDEX out of range");
|
||||
}
|
||||
this->dot_index = m_dot_index;
|
||||
}
|
||||
|
||||
int Item::get_dot_next_symbol() const {
|
||||
if(get_dot_index() == production->right.size()) {
|
||||
return 0;
|
||||
} else {
|
||||
return production->right[dot_index];
|
||||
}
|
||||
}
|
||||
|
||||
int Item::get_dot_next_i_symbol(int i) const {
|
||||
if(get_dot_index() + i >= production->right.size()) {
|
||||
return 0;
|
||||
} else {
|
||||
return production->right[dot_index + i];
|
||||
}
|
||||
}
|
124
src/ItemCollection.cpp
Normal file
124
src/ItemCollection.cpp
Normal file
@ -0,0 +1,124 @@
|
||||
//
|
||||
// Created by Administrator on 2021/4/30.
|
||||
//
|
||||
#include "ItemCollection.h"
|
||||
|
||||
size_t ItemCollection::getHash() const {
|
||||
size_t seed = 0;
|
||||
|
||||
std::vector<Item *> cache_sorted(cache.begin(), cache.end());
|
||||
std::sort(cache_sorted.begin(), cache_sorted.end(), compare_item_ptr);
|
||||
|
||||
for(const auto item : cache_sorted) {
|
||||
|
||||
if(item->generated) {
|
||||
continue;
|
||||
}
|
||||
|
||||
hash_combine(seed, item->get_production());
|
||||
hash_combine(seed, item->get_dot_index());
|
||||
hash_combine(seed, item->get_terminator());
|
||||
}
|
||||
return seed;
|
||||
}
|
||||
|
||||
void ItemCollection::print(std::wofstream &output) const {
|
||||
|
||||
output << L"I" << index << L": ";
|
||||
|
||||
for(const auto item : cache) {
|
||||
const auto *p_pdt = item->get_production();
|
||||
int dot_index = item->get_dot_index();
|
||||
output << pool->getSymbol(p_pdt->left)->name << L" -> ";
|
||||
int i = 0;
|
||||
for(const auto &symbol_index : p_pdt->right) {
|
||||
|
||||
if(i > 0) output << " ";
|
||||
if(i++ == dot_index) output << "*";
|
||||
|
||||
auto *symbol = pool->getSymbol(symbol_index);
|
||||
|
||||
if(!symbol->index) {
|
||||
output << L"[Epsilon]";
|
||||
continue;
|
||||
}
|
||||
|
||||
if(!symbol->terminator)
|
||||
output << pool->getSymbol(symbol_index)->name;
|
||||
else
|
||||
output << L'"' << pool->getSymbol(symbol_index)->name << L'"';
|
||||
}
|
||||
|
||||
if(i++ == dot_index) output << "*";
|
||||
|
||||
output << L", \"" << pool->getSymbol(item->get_terminator())->name << "\"" << std::endl;
|
||||
}
|
||||
output << std::endl;
|
||||
}
|
||||
|
||||
void ItemCollection::CLOSURE() {
|
||||
|
||||
bool ifAdd = true;
|
||||
|
||||
while(ifAdd) {
|
||||
ifAdd = false;
|
||||
|
||||
for(const auto & item : items) {
|
||||
int next_symbol = item.second->get_dot_next_symbol();
|
||||
|
||||
if(next_symbol == 0
|
||||
|| pool->getSymbol(next_symbol)->terminator) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for(auto *production : pool->get_productions()) {
|
||||
if(production->left == next_symbol) {
|
||||
std::vector<int> first_args;
|
||||
auto p_ic = item.second;
|
||||
const auto last_right_symbol_count = p_ic->get_right_size() - p_ic->get_dot_index();
|
||||
for(int i = 1; i <= last_right_symbol_count; i++)
|
||||
first_args.push_back(p_ic->get_dot_next_i_symbol(i));
|
||||
first_args.push_back(p_ic->get_terminator());
|
||||
|
||||
const auto first_set = pool->FIRST(first_args, 0);
|
||||
for(auto terminator : *first_set) {
|
||||
if(terminator == 0) continue;
|
||||
if(this->addItem(production, 0, terminator, true)) {
|
||||
ifAdd = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool ItemCollection::addItem(const Production *p_pdt, int dot_index, int terminator, bool generated) {
|
||||
auto hasher = std::hash<int>();
|
||||
size_t seed = hasher(reinterpret_cast<const int>(p_pdt));
|
||||
hash_combine(seed, dot_index);
|
||||
hash_combine(seed, terminator);
|
||||
|
||||
auto it = items.find(seed);
|
||||
if(it != items.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto *p_item = new Item(p_pdt, terminator, generated);
|
||||
p_item->set_dot_index(dot_index);
|
||||
items.insert(std::pair<size_t, Item *>(seed, p_item));
|
||||
cache.push_back(p_item);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ItemCollection::compare_item_ptr(const Item *lhs, const Item *rhs) {
|
||||
if(lhs->get_production() != rhs->get_production())
|
||||
return lhs->get_production() < rhs->get_production();
|
||||
else if(lhs->get_dot_index() != rhs->get_dot_index())
|
||||
return lhs->get_dot_index() < rhs->get_dot_index();
|
||||
else
|
||||
return lhs->get_terminator() < rhs->get_terminator();
|
||||
}
|
131
src/ItemCollectionManager.cpp
Normal file
131
src/ItemCollectionManager.cpp
Normal file
@ -0,0 +1,131 @@
|
||||
//
|
||||
// Created by Administrator on 2021/4/30.
|
||||
//
|
||||
|
||||
#include "ItemCollectionManager.h"
|
||||
|
||||
void ItemCollectionManager::buildItems() {
|
||||
|
||||
const auto startSymbol = pool->getStartSymbol();
|
||||
|
||||
std::wstring new_symbol_name = startSymbol->name + L"'";
|
||||
|
||||
int new_symbol_index = pool->addSymbol(new_symbol_name, startSymbol->terminator);
|
||||
|
||||
pool->modifySymbol(startSymbol->index, startSymbol->name.substr(1), false, false);
|
||||
|
||||
const auto *p_pdt = pool->addProduction(new_symbol_index, {startSymbol->index});
|
||||
|
||||
this->start_pdt = p_pdt;
|
||||
|
||||
auto *pi_ic = new ItemCollection(pool);
|
||||
|
||||
// -1 ´ú±í $
|
||||
pi_ic->addItem(p_pdt, 0, -1);
|
||||
|
||||
pi_ic->CLOSURE();
|
||||
|
||||
addItemCollection(0, 0, pi_ic);
|
||||
|
||||
bool ifAdd = true;
|
||||
|
||||
while(ifAdd) {
|
||||
|
||||
ifAdd = false;
|
||||
const auto &r_ics = getItemCollections();
|
||||
std::vector<const ItemCollection *> temp_ics(r_ics.begin(), r_ics.end());
|
||||
for(const auto ic : temp_ics) {
|
||||
for(const auto symbol : pool->getAllSymbols()) {
|
||||
if(symbol->index <= 0) {
|
||||
continue;
|
||||
}
|
||||
if(GOTO(ic, symbol->index)) {
|
||||
ifAdd = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ItemCollection *ItemCollectionManager::getItemCollectionByHash(size_t hash) {
|
||||
ItemCollection *p_ic = nullptr;
|
||||
auto it = ic_content_map.find(hash);
|
||||
if(it != ic_content_map.end()) {
|
||||
p_ic = it->second;
|
||||
}
|
||||
return p_ic;
|
||||
}
|
||||
|
||||
bool ItemCollectionManager::addItemCollection(int idx, int symbol, ItemCollection *p_ic) {
|
||||
|
||||
size_t ic_hash = p_ic->getHash();
|
||||
auto it = ic_content_map.find(ic_hash);
|
||||
if (it != ic_content_map.end()) {
|
||||
p_ic = it->second;
|
||||
} else {
|
||||
p_ic->index = this->index++;
|
||||
ic_content_map.insert(std::pair<size_t, ItemCollection *>(ic_hash, p_ic));
|
||||
ics.push_back(p_ic);
|
||||
}
|
||||
|
||||
auto hasher = std::hash<int>();
|
||||
size_t seed = hasher(idx);
|
||||
hash_combine(seed, symbol);
|
||||
|
||||
auto it2 = ic_map.find(seed);
|
||||
if(it2 != ic_map.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(symbol != 0) {
|
||||
auto p_symbol = pool->getSymbol(symbol);
|
||||
if(p_symbol->terminator)
|
||||
output << L"GOTO(" << idx << L", \"" << p_symbol->name << L"\")" << std::endl;
|
||||
else
|
||||
output << L"GOTO(" << idx << L", " << p_symbol->name << L")" << std::endl;
|
||||
} else {
|
||||
output << L"GOTO(" << idx << L", [Epsilon])" << std::endl;
|
||||
}
|
||||
|
||||
ic_map.insert(std::pair<size_t, ItemCollection *>(seed, p_ic));
|
||||
p_ic->print(output);
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
const ItemCollection *ItemCollectionManager::getGOTO(int idx, int symbol) const {
|
||||
|
||||
auto hasher = std::hash<int>();
|
||||
size_t seed = hasher(idx);
|
||||
hash_combine(seed, symbol);
|
||||
|
||||
auto it = ic_map.find(seed);
|
||||
if(it != ic_map.end()) {
|
||||
return it->second;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool ItemCollectionManager::GOTO(const ItemCollection *p_ic, int symbol) {
|
||||
auto *pt_ic = new ItemCollection(pool);
|
||||
|
||||
for(const auto &item : p_ic->cache) {
|
||||
if(item->get_dot_next_symbol() == symbol) {
|
||||
pt_ic->addItem(item->get_production(), item->get_dot_index() + 1, item->get_terminator());
|
||||
}
|
||||
}
|
||||
auto p_temp_ic = this->getItemCollectionByHash(pt_ic->getHash());
|
||||
if(p_temp_ic == nullptr)
|
||||
pt_ic->CLOSURE();
|
||||
else pt_ic = p_temp_ic;
|
||||
|
||||
if(!pt_ic->items.empty()) {
|
||||
return this->addItemCollection(p_ic->index, symbol, pt_ic);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
17
src/LR1Generator.cpp
Normal file
17
src/LR1Generator.cpp
Normal file
@ -0,0 +1,17 @@
|
||||
//
|
||||
// Created by Administrator on 2021/4/30.
|
||||
//
|
||||
|
||||
#include "LR1Generator.h"
|
||||
|
||||
void LR1Generator::getProductions() {
|
||||
|
||||
// 读入文法文件
|
||||
std::wstring temp_line;
|
||||
|
||||
while (getline(input, temp_line)) {
|
||||
if(temp_line.size() > 2 && temp_line[0] != '#') {
|
||||
pool->parse_production_string_line(temp_line);
|
||||
}
|
||||
}
|
||||
}
|
5
src/Production.cpp
Normal file
5
src/Production.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
//
|
||||
// Created by Administrator on 2021/4/30.
|
||||
//
|
||||
|
||||
#include "Production.h"
|
5
src/Symbol.cpp
Normal file
5
src/Symbol.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
//
|
||||
// Created by Administrator on 2021/4/30.
|
||||
//
|
||||
|
||||
#include "Symbol.h"
|
81
src/SymbolTable.cpp
Normal file
81
src/SymbolTable.cpp
Normal file
@ -0,0 +1,81 @@
|
||||
//
|
||||
// Created by Administrator on 2021/4/30.
|
||||
//
|
||||
|
||||
#include "SymbolTable.h"
|
||||
|
||||
SymbolTable::SymbolTable() {
|
||||
|
||||
auto symbol = new Symbol(0, L"¦Å", true, false);
|
||||
table.insert(std::pair<std::wstring, Symbol *>(L"¦Å", symbol));
|
||||
cache.insert(std::pair<int, Symbol *>(0, symbol));
|
||||
line.push_back(symbol);
|
||||
|
||||
symbol = new Symbol(-1, L"$", true, false);
|
||||
table.insert(std::pair<std::wstring, Symbol *>(L"$", symbol));
|
||||
cache.insert(std::pair<int, Symbol *>(-1, symbol));
|
||||
line.push_back(symbol);
|
||||
}
|
||||
|
||||
int SymbolTable::addSymbol(const std::wstring &name, bool terminator) {
|
||||
|
||||
Symbol *symbol = nullptr;
|
||||
|
||||
if(name == L"¦Å") {
|
||||
return 0;
|
||||
} else if (name[0] == L'@') {
|
||||
symbol = new Symbol(index, name, terminator, true);
|
||||
} else {
|
||||
symbol = new Symbol(index, name, terminator, false);
|
||||
}
|
||||
|
||||
const auto &it = table.find(name);
|
||||
if (it != table.end()) {
|
||||
return it->second->index;
|
||||
}
|
||||
table.insert(std::pair<std::wstring, Symbol *>(symbol->name, symbol));
|
||||
cache.insert(std::pair<int, Symbol *>(symbol->index, symbol));
|
||||
line.push_back(symbol);
|
||||
|
||||
index++;
|
||||
|
||||
return symbol->index;
|
||||
}
|
||||
|
||||
const Symbol *SymbolTable::getSymbol(int symbol_index) const {
|
||||
const auto &it = cache.find(symbol_index);
|
||||
if(it != cache.end()) {
|
||||
return it->second;
|
||||
} else {
|
||||
throw std::runtime_error("symbol " + std::to_string(symbol_index) + " NOT Found");
|
||||
}
|
||||
}
|
||||
|
||||
int SymbolTable::getSymbolIndex(const std::wstring &name) const {
|
||||
const auto &it = table.find(name);
|
||||
if(it != table.end()) {
|
||||
return it->second->index;
|
||||
} else {
|
||||
throw std::runtime_error("symbol NOT Found");
|
||||
}
|
||||
}
|
||||
|
||||
void SymbolTable::modifySymbol(int idx, const std::wstring &name, bool terminator, bool start) {
|
||||
auto it = cache.find(idx);
|
||||
if(it != cache.end()) {
|
||||
auto p_sym = it->second;
|
||||
p_sym->name = name;
|
||||
p_sym->terminator = terminator;
|
||||
p_sym->start = start;
|
||||
}
|
||||
}
|
||||
|
||||
const Symbol *SymbolTable::getStartSymbol() const {
|
||||
for(const auto & symbol : getAllSymbols()) {
|
||||
if(symbol->start) {
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
|
||||
throw std::runtime_error("start symbol NOT Found");
|
||||
}
|
173
src/SyntaxParser.cpp
Normal file
173
src/SyntaxParser.cpp
Normal file
@ -0,0 +1,173 @@
|
||||
//
|
||||
// Created by Administrator on 2021/4/30.
|
||||
//
|
||||
|
||||
#include "SyntaxParser.h"
|
||||
|
||||
void SyntaxParser::parse() {
|
||||
status_stack.push(0);
|
||||
|
||||
now_line = 1;
|
||||
size_t _line_index = 0, max_line_index = lines_index[now_line-1];
|
||||
while(!tokens_queue.empty()) {
|
||||
|
||||
auto *p_step = atg->findActionStep(status_stack.top(), tokens_queue.front());
|
||||
|
||||
if(p_step == nullptr) {
|
||||
printError();
|
||||
return;
|
||||
}
|
||||
|
||||
if(p_step->action == MOVE) {
|
||||
output << "MOVE IN" << "(AUTOMATA STATUS " << status_stack.top() <<"): ";
|
||||
printSymbol(tokens_queue.front());
|
||||
|
||||
status_stack.push(p_step->target.index);
|
||||
analyse_stack.push(tokens_queue.front());
|
||||
|
||||
if(_line_index > max_line_index) {
|
||||
string_buffer.str(L"");
|
||||
string_buffer.clear();
|
||||
max_line_index = lines_index[now_line++];
|
||||
}
|
||||
string_buffer << pool->getSymbol(tokens_queue.front())->name << " ";
|
||||
tokens_queue.pop();
|
||||
_line_index++;
|
||||
}
|
||||
else if(p_step->action == REDUCE) {
|
||||
|
||||
auto *p_pdt = p_step->target.production;
|
||||
output << "REDUCE BY" << "(AUTOMATA STATUS " << status_stack.top() <<"): [";
|
||||
printProduction(p_pdt);
|
||||
output << "]";
|
||||
|
||||
for(int i : p_pdt->right) {
|
||||
if(i == 0)
|
||||
continue;
|
||||
analyse_stack.pop();
|
||||
status_stack.pop();
|
||||
}
|
||||
|
||||
auto *p_goto_step =
|
||||
atg->findGotoStep(status_stack.top(), p_pdt->left);
|
||||
|
||||
if(p_goto_step == nullptr) {
|
||||
printError();
|
||||
return;
|
||||
}
|
||||
|
||||
analyse_stack.push(p_pdt->left);
|
||||
status_stack.push(p_goto_step->target.index);
|
||||
|
||||
} else if (p_step->action == ACC) {
|
||||
output << "ACC";
|
||||
printDone();
|
||||
return;
|
||||
} else {
|
||||
printError();
|
||||
return;
|
||||
}
|
||||
|
||||
output << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void SyntaxParser::printProduction(const Production *p_pdt) {
|
||||
output << pool->getSymbol(p_pdt->left)->name << L" -> " ;
|
||||
int i = 0;
|
||||
for(const auto &symbol_index : p_pdt->right) {
|
||||
|
||||
if(i++ > 0) output << " ";
|
||||
|
||||
printSymbol(symbol_index);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void SyntaxParser::printSymbol(int symbol_index) {
|
||||
auto *symbol = pool->getSymbol(symbol_index);
|
||||
|
||||
if(!symbol->index) {
|
||||
output << L"[Epsilon]";
|
||||
return;
|
||||
}
|
||||
if(!symbol->terminator)
|
||||
output << pool->getSymbol(symbol_index)->name;
|
||||
else
|
||||
output << L'"' << pool->getSymbol(symbol_index)->name << L'"';
|
||||
}
|
||||
|
||||
void SyntaxParser::getToken() {
|
||||
|
||||
// 读入文法文件
|
||||
std::wstring temp_line;
|
||||
|
||||
size_t _line_index = 0;
|
||||
while (getline(input, temp_line)) {
|
||||
if(temp_line.size() > 2 && temp_line[0] != '#') {
|
||||
std::vector<std::wstring> tokens = ws_split(temp_line, L" ");
|
||||
|
||||
for(int i = 1; i < tokens.size(); i++) {
|
||||
if(tokens[i] == L"\r") continue;;
|
||||
auto token_info = get_token_info(tokens[i]);
|
||||
int symbol_index;
|
||||
|
||||
if(token_info.first == L"ID"
|
||||
|| token_info.first == L"EOF"
|
||||
|| token_info.first == L"INTEGER"
|
||||
|| token_info.first == L"STRING")
|
||||
symbol_index = pool->getSymbolIndex(token_info.first);
|
||||
else
|
||||
symbol_index = pool->getSymbolIndex(token_info.second);
|
||||
|
||||
tokens_queue.push(symbol_index);
|
||||
_line_index++;
|
||||
|
||||
}
|
||||
lines_index.push_back(_line_index - 1);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// 加入终结符$
|
||||
tokens_queue.push(-1);
|
||||
}
|
||||
|
||||
std::vector<std::wstring> SyntaxParser::ws_split(const std::wstring &in, const std::wstring &delim) {
|
||||
std::wregex re{ delim };
|
||||
return std::vector<std::wstring> {
|
||||
std::wsregex_token_iterator(in.begin(), in.end(), re, -1),
|
||||
std::wsregex_token_iterator()
|
||||
};
|
||||
}
|
||||
|
||||
std::pair<std::wstring, std::wstring> SyntaxParser::get_token_info(const std::wstring &token) {
|
||||
|
||||
auto pre_index = token.find(L'(');
|
||||
|
||||
auto back_index = token.find(L')');
|
||||
|
||||
std::wstring name = token.substr(0, pre_index);
|
||||
std::wstring value = token.substr(pre_index + 1, back_index - pre_index - 1);
|
||||
|
||||
return std::pair<std::wstring, std::wstring>(name, value);
|
||||
|
||||
}
|
||||
|
||||
void SyntaxParser::printDone() {
|
||||
output << std::endl;
|
||||
output << "------------------------------------------------------" << std::endl;
|
||||
output << "Syntax Parser Work Done, No Error Found." << std::endl << std::endl;
|
||||
}
|
||||
|
||||
void SyntaxParser::printError() {
|
||||
std::wstring temp_line = string_buffer.str();
|
||||
output << std::endl;
|
||||
output << "------------------------------------------------------" << std::endl;
|
||||
output.fill('-');
|
||||
output.width(24);
|
||||
output << "Syntax Parser Found Error: " << std::endl
|
||||
<< "At [Line " << now_line << "]: " << temp_line
|
||||
<< "<- Next Token{" << pool->getSymbol(tokens_queue.front())->name << "}" << std::endl;
|
||||
output << "AUTOMATA STATUS " << status_stack.top() << std::endl;
|
||||
}
|
Loading…
Reference in New Issue
Block a user