lexer,parser,import,codegen use the same error module.

This commit is contained in:
ValKmjolnir 2021-12-23 21:15:50 +08:00
parent 30650bb64f
commit f0ae63bce5
11 changed files with 160 additions and 136 deletions

View File

@ -51,12 +51,6 @@ void logo()
<<"input <nasal -h> to get help .\n";
}
void die(const char* stage,const std::string& filename)
{
std::cout<<"["<<stage<<"] in <"<<filename<<">: error(s) occurred,stop.\n";
std::exit(1);
}
void err()
{
std::cout
@ -67,43 +61,37 @@ void err()
void execute(const std::string& file,const uint32_t cmd)
{
nasal_lexer lexer;
nasal_parse parse;
nasal_import linker;
nasal_codegen gen;
// front end use the same error module
nasal_err nerr;
nasal_lexer lexer(nerr);
nasal_parse parse(nerr);
nasal_import linker(nerr);
nasal_codegen gen(nerr);
// back end
nasal_vm vm;
// lexer scans file to get tokens
lexer.scan(file);
if(lexer.err())
die("lexer",file);
if(cmd&VM_LEXINFO)
lexer.print();
// parser gets lexer's token list to compile
parse.compile(lexer);
if(parse.err())
die("parse",file);
// linker gets parser's ast and load import files to this ast
linker.link(parse,file);
if(linker.err())
die("import",file);
if(cmd&VM_ASTINFO)
parse.print();
// code generator gets parser's ast and linker's import file list to generate code
gen.compile(parse,linker);
if(gen.err())
die("code",file);
if(cmd&VM_CODEINFO)
gen.print();
// run bytecode
if(cmd&VM_DEBUG)
{
nasal_dbg dbg;
dbg.run(gen,linker);
nasal_dbg debugger;
debugger.run(gen,linker);
}
else if(cmd&VM_EXECTIME)
{
@ -119,7 +107,7 @@ int main(int argc,const char* argv[])
{
if(argc==1)
{
help();
logo();
return 0;
}
if(argc==2)

View File

@ -1,5 +1,5 @@
.PHONY=test
nasal:main.cpp nasal_ast.h nasal_builtin.h nasal_codegen.h nasal_gc.h nasal_import.h nasal_lexer.h nasal_parse.h nasal_vm.h nasal_dbg.h nasal.h
nasal:main.cpp nasal_ast.h nasal_err.h nasal_builtin.h nasal_codegen.h nasal_gc.h nasal_import.h nasal_lexer.h nasal_parse.h nasal_vm.h nasal_dbg.h nasal.h
clang++ -std=c++11 -O3 main.cpp -o nasal -fno-exceptions -ldl -Wshadow -Wall
test:nasal
./nasal test/ascii-art.nas
@ -11,18 +11,18 @@ test:nasal
./nasal test/calc.nas
./nasal test/choice.nas
./nasal test/class.nas
# ./nasal test/exception.nas
./nasal -c test/exception.nas
./nasal -t test/fib.nas
./nasal test/filesystem.nas
./nasal test/hexdump.nas
./nasal test/json.nas
./nasal test/leetcode1319.nas
./nasal test/lexer.nas
./nasal -c test/life.nas
./nasal test/life.nas
./nasal -t test/loop.nas
./nasal -c test/mandel.nas
./nasal -t test/mandelbrot.nas
# ./nasal -t test/module_test.nas
./nasal -c test/module_test.nas
./nasal test/nasal_test.nas
./nasal -t test/pi.nas
./nasal -t test/prime.nas

View File

@ -127,6 +127,7 @@ std::string rawstr(const std::string& str)
}
return ret;
}
#include "nasal_err.h"
#include "nasal_lexer.h"
#include "nasal_ast.h"
#include "nasal_parse.h"

View File

@ -193,6 +193,7 @@ class nasal_codegen
private:
uint32_t error;
uint16_t fileindex;
nasal_err& nerr;
const std::string* file;
std::stack<uint32_t> in_iterloop;
std::unordered_map<double,int> num_table;
@ -205,7 +206,7 @@ private:
std::vector<std::string> global; // global : max 4095 values
std::list<std::vector<std::string>> local; // local : max 32768 upvalues 65536 values
void die(const std::string,const int);
void die(const std::string&,const uint32_t);
void regist_number(const double);
void regist_string(const std::string&);
void find_symbol(const nasal_ast&);
@ -246,6 +247,7 @@ private:
void block_gen(const nasal_ast&);
void ret_gen(const nasal_ast&);
public:
nasal_codegen(nasal_err& e):nerr(e){}
uint32_t err(){return error;}
void compile(const nasal_parse&,const nasal_import&);
void print_op(uint32_t);
@ -255,10 +257,10 @@ public:
const std::vector<opcode>& get_code() const {return code;}
};
void nasal_codegen::die(const std::string info,const int line)
void nasal_codegen::die(const std::string& info,const uint32_t line)
{
++error;
std::cout<<"[code] <"<<file[fileindex]<<":"<<line<<"> "<<info<<"\n";
nerr.load(file[fileindex]);
nerr.err("code",line,info.c_str());
}
void nasal_codegen::regist_number(const double num)
@ -1217,6 +1219,7 @@ void nasal_codegen::compile(const nasal_parse& parse,const nasal_import& import)
gen(op_exit,0,0);
if(global.size()>=STACK_MAX_DEPTH)
die("too many global variants: "+std::to_string(global.size())+".",0);
nerr.chkerr();
}
void nasal_codegen::print_op(uint32_t index)

View File

@ -7,22 +7,19 @@ class nasal_dbg:public nasal_vm
{
private:
bool next_step;
uint16_t last_fidx;
uint16_t bk_fidx;
uint32_t bk_line;
std::vector<std::string> src;
file_line src;
std::vector<std::string> parse(std::string&);
uint16_t get_fileindex(std::string&);
std::vector<std::string> parse(const std::string&);
uint16_t get_fileindex(const std::string&);
void err();
void help();
void load_src(const std::string&);
void stepinfo();
void interact();
public:
nasal_dbg():
next_step(false),
last_fidx(0),
bk_fidx(0),bk_line(0){}
void run(
const nasal_codegen&,
@ -30,7 +27,7 @@ public:
);
};
std::vector<std::string> nasal_dbg::parse(std::string& cmd)
std::vector<std::string> nasal_dbg::parse(const std::string& cmd)
{
std::vector<std::string> res;
std::string tmp="";
@ -49,7 +46,7 @@ std::vector<std::string> nasal_dbg::parse(std::string& cmd)
return res;
}
uint16_t nasal_dbg::get_fileindex(std::string& filename)
uint16_t nasal_dbg::get_fileindex(const std::string& filename)
{
for(uint16_t i=0;i<files_size;++i)
if(filename==files[i])
@ -81,30 +78,11 @@ void nasal_dbg::help()
<<"\tbk, break | set break point\n";
}
void nasal_dbg::load_src(const std::string& filename)
{
src.clear();
std::ifstream fin(filename,std::ios::binary);
if(fin.fail())
{
std::cout<<"[debug] cannot open source code file <"<<filename<<">\n";
std::exit(-1);
}
std::string tmp;
while(!fin.eof())
{
std::getline(fin,tmp);
src.push_back(tmp);
}
}
void nasal_dbg::stepinfo()
{
uint32_t begin,end;
uint32_t line=bytecode[pc].line==0?0:bytecode[pc].line-1;
if(bytecode[pc].fidx!=last_fidx)
load_src(files[bytecode[pc].fidx]);
last_fidx=bytecode[pc].fidx;
src.load(files[bytecode[pc].fidx]);
printf("source code:\n");
begin=(line>>3)==0?0:((line>>3)<<3);
end=(1+(line>>3))<<3;
@ -203,7 +181,6 @@ void nasal_dbg::run(
{
detail_info=true;
init(gen.get_strs(),gen.get_nums(),linker.get_file());
load_src(files[0]);
const void* opr_table[]=
{
&&nop, &&intg, &&intl, &&loadg,

70
nasal_err.h Normal file
View File

@ -0,0 +1,70 @@
#ifndef __NASAL_ERR_H__
#define __NASAL_ERR_H__
#include <iostream>
#include <fstream>
#include <cstring>
class file_line
{
protected:
std::string file;
std::vector<std::string> res;
public:
void load(const std::string& f)
{
if(file==f)
return;
file=f;
res.clear();
std::ifstream fin(f,std::ios::binary);
if(fin.fail())
{
std::cout<<"[src] cannot open file <"<<f<<">\n";
std::exit(1);
}
std::string line;
while(!fin.eof())
{
std::getline(fin,line);
res.push_back(line);
}
}
void clear()
{
std::vector<std::string> tmp;
res.swap(tmp);
}
const std::string& operator[](const uint32_t line){return res[line];}
const std::string& name(){return file;}
size_t size(){return res.size();}
};
class nasal_err:public file_line
{
private:
uint32_t error;
public:
void err(const char* stage,const std::string& info)
{
++error;
std::cout<<"["<<stage<<"] "<<info<<'\n';
}
void err(const char* stage,uint32_t line,uint32_t column,const std::string& info)
{
++error;
std::cout<<"["<<stage<<"] "<<file<<":"<<line<<":"<<column<<" "<<info<<"\n"<<res[line-1]<<'\n';
for(int i=0;i<(int)column-1;++i)
std::cout<<char(" \t"[res[line-1][i]=='\t']);
std::cout<<"^\n";
}
void err(const char* stage,uint32_t line,const std::string& info)
{
++error;
std::cout<<"["<<stage<<"] "<<file<<":"<<line<<" "<<info<<"\n"<<res[line-1]<<'\n';
}
void chkerr(){if(error)std::exit(1);}
};
#endif

View File

@ -4,26 +4,19 @@
class nasal_import
{
private:
uint32_t error;
nasal_err& nerr;
std::vector<std::string> files;
void die(const std::string&,const char*);
bool check_import(const nasal_ast&);
bool check_exist(const std::string&);
void linker(nasal_ast&,nasal_ast&&);
nasal_ast file_import(nasal_ast&);
nasal_ast load(nasal_ast&,uint16_t);
public:
uint32_t err(){return error;}
void link(nasal_parse&,const std::string&);
nasal_import(nasal_err& e):nerr(e){}
void link(nasal_parse&,const std::string&);
const std::vector<std::string>& get_file() const {return files;}
};
void nasal_import::die(const std::string& file,const char* stage)
{
++error;
std::cout<<"[import] in <\""<<file<<"\">: error(s) occurred in "<<stage<<".\n";
}
bool nasal_import::check_import(const nasal_ast& node)
{
/*
@ -65,8 +58,8 @@ void nasal_import::linker(nasal_ast& root,nasal_ast&& add_root)
nasal_ast nasal_import::file_import(nasal_ast& node)
{
nasal_lexer lex;
nasal_parse par;
nasal_lexer lex(nerr);
nasal_parse par(nerr);
// get filename and set node to ast_null
std::string filename=node[1][0].str();
node.clear();
@ -77,17 +70,7 @@ nasal_ast nasal_import::file_import(nasal_ast& node)
// start importing...
lex.scan(filename);
if(lex.err())
{
die(filename,"lexer");
return {0,ast_root};
}
par.compile(lex);
if(par.err())
{
die(filename,"parser");
return {0,ast_root};
}
nasal_ast tmp=std::move(par.ast());
// check if tmp has 'import'
return load(tmp,files.size()-1);
@ -110,7 +93,6 @@ nasal_ast nasal_import::load(nasal_ast& root,uint16_t fileindex)
void nasal_import::link(nasal_parse& parse,const std::string& self)
{
// initializing
error=0;
files={self};
// scan root and import files,then generate a new ast and return to import_ast
// the main file's index is 0

View File

@ -90,30 +90,36 @@ struct
struct token
{
uint32_t line;
uint32_t column;
uint32_t type;
std::string str;
token(uint32_t l=0,uint32_t t=tok_null,std::string s=""){line=l;type=t;str=s;}
token(uint32_t l=0,uint32_t c=0,uint32_t t=tok_null,std::string s="")
{
line=l;
column=c;
type=t;
str=s;
}
};
class nasal_lexer
{
private:
uint32_t error;
uint32_t line;
uint32_t column;
uint32_t ptr;
std::string filename;
std::string code;
nasal_err& nerr;
std::string res;
std::vector<token> tokens;
uint32_t get_type(const std::string&);
void die(const char*);
void die(const char* info){nerr.err("lexer",line,column,info);};
void open(const std::string&);
std::string id_gen();
std::string num_gen();
std::string str_gen();
public:
uint32_t err(){return error;}
nasal_lexer(nasal_err& e):nerr(e){}
void scan(const std::string&);
void print();
const std::vector<token>& get_tokens() const {return tokens;}
@ -121,13 +127,11 @@ public:
void nasal_lexer::open(const std::string& file)
{
filename=file;
std::ifstream fin(file,std::ios::binary);
if(fin.fail())
{
++error;
std::cout<<"[lexer] cannot open file <"<<file<<">.\n";
}
nerr.err("lexer","cannot open file <"+file+">.");
else
nerr.load(file);
std::stringstream ss;
ss<<fin.rdbuf();
res=ss.str();
@ -141,21 +145,12 @@ uint32_t nasal_lexer::get_type(const std::string& tk_str)
return tok_null;
}
void nasal_lexer::die(const char* info)
{
++error;
std::cout<<"[lexer] "<<filename<<":"<<line<<":"<<code.length()<<"\n"<<code<<'\n';
for(int i=0;i<(int)code.size()-1;++i)
std::cout<<char(" \t"[code[i]=='\t']);
std::cout<<'^'<<info<<'\n';
}
std::string nasal_lexer::id_gen()
{
std::string str="";
while(ptr<res.size() && (ID(res[ptr])||DIGIT(res[ptr])))
str+=res[ptr++];
code+=str;
column+=str.length();
return str;
}
@ -168,7 +163,7 @@ std::string nasal_lexer::num_gen()
ptr+=2;
while(ptr<res.size() && HEX(res[ptr]))
str+=res[ptr++];
code+=str;
column+=str.length();
if(str.length()<3)// "0x"
die("invalid number.");
return str;
@ -180,7 +175,7 @@ std::string nasal_lexer::num_gen()
ptr+=2;
while(ptr<res.size() && OCT(res[ptr]))
str+=res[ptr++];
code+=str;
column+=str.length();
if(str.length()<3)// "0o"
die("invalid number.");
return str;
@ -198,7 +193,7 @@ std::string nasal_lexer::num_gen()
// "xxxx." is not a correct number
if(str.back()=='.')
{
code+=str;
column+=str.length();
die("invalid number.");
return "0";
}
@ -213,12 +208,12 @@ std::string nasal_lexer::num_gen()
// "xxxe(-|+)" is not a correct number
if(str.back()=='e' || str.back()=='E' || str.back()=='-' || str.back()=='+')
{
code+=str;
column+=str.length();
die("invalid number.");
return "0";
}
}
code+=str;
column+=str.length();
return str;
}
@ -226,18 +221,19 @@ std::string nasal_lexer::str_gen()
{
std::string str="";
char begin=res[ptr];
code+=begin;
++column;
while(++ptr<res.size() && res[ptr]!=begin)
{
code+=res[ptr];
++column;
if(res[ptr]=='\n')
{
code="";
column=0;
++line;
}
if(res[ptr]=='\\' && ptr+1<res.size())
{
code+=res[++ptr];
++column;
++ptr;
switch(res[ptr])
{
case '0': str+='\0'; break;
@ -264,7 +260,7 @@ std::string nasal_lexer::str_gen()
die("get EOF when generating string.");
return str;
}
code+=res[ptr-1];
++column;
if(begin=='`' && str.length()!=1)
die("\'`\' is used for string that includes one character.");
return str;
@ -273,7 +269,8 @@ std::string nasal_lexer::str_gen()
void nasal_lexer::scan(const std::string& file)
{
line=1;
error=ptr=0;
column=0;
ptr=0;
open(file);
std::string str;
@ -282,11 +279,11 @@ void nasal_lexer::scan(const std::string& file)
while(ptr<res.size() && (res[ptr]==' ' || res[ptr]=='\n' || res[ptr]=='\t' || res[ptr]=='\r' || res[ptr]<0))
{
// these characters will be ignored, and '\n' will cause ++line
code+=res[ptr];
++column;
if(res[ptr++]=='\n')
{
++line;
code="";
column=0;
}
}
if(ptr>=res.size()) break;
@ -294,20 +291,20 @@ void nasal_lexer::scan(const std::string& file)
{
str=id_gen();
uint32_t type=get_type(str);
tokens.push_back({line,type?type:tok_id,str});
tokens.push_back({line,column,type?type:tok_id,str});
}
else if(DIGIT(res[ptr]))
tokens.push_back({line,tok_num,num_gen()});
tokens.push_back({line,column,tok_num,num_gen()});
else if(STR(res[ptr]))
tokens.push_back({line,tok_str,str_gen()});
tokens.push_back({line,column,tok_str,str_gen()});
else if(SINGLE_OPERATOR(res[ptr]))
{
str=res[ptr];
code+=res[ptr];
++column;
uint32_t type=get_type(str);
if(!type)
die("invalid operator.");
tokens.push_back({line,type,str});
tokens.push_back({line,column,type,str});
++ptr;
}
else if(res[ptr]=='.')
@ -316,8 +313,8 @@ void nasal_lexer::scan(const std::string& file)
if(ptr+2<res.size() && res[ptr+1]=='.' && res[ptr+2]=='.')
str+="..";
ptr+=str.length();
code+=str;
tokens.push_back({line,get_type(str),str});
column+=str.length();
tokens.push_back({line,column,get_type(str),str});
}
else if(CALC_OPERATOR(res[ptr]))
{
@ -325,19 +322,21 @@ void nasal_lexer::scan(const std::string& file)
str=res[ptr++];
if(ptr<res.size() && res[ptr]=='=')
str+=res[ptr++];
code+=str;
tokens.push_back({line,get_type(str),str});
column+=str.length();
tokens.push_back({line,column,get_type(str),str});
}
else if(NOTE(res[ptr]))// avoid note, after this process ptr will point to a '\n', so next loop line counter+1
while(++ptr<res.size() && res[ptr]!='\n');
else
{
code+=res[ptr++];
++column;
++ptr;
die("unknown character.");
}
}
tokens.push_back({line,tok_eof,"eof"});
code=res="";
tokens.push_back({line,column,tok_eof,"eof"});
res="";
nerr.chkerr();
}
void nasal_lexer::print()

View File

@ -42,11 +42,11 @@ class nasal_parse
#define is_call(type) ((type)==tok_lcurve || (type)==tok_lbracket || (type)==tok_dot)
private:
uint32_t ptr;
uint32_t error;
uint32_t in_func; // count function block
uint32_t in_loop; // count loop block
const token* tokens;// ref from nasal_lexer
nasal_ast root;
nasal_err& nerr;
void die(uint32_t,const std::string&);
void match(uint32_t type,const char* info=nullptr);
@ -98,7 +98,7 @@ private:
nasal_ast break_expr();
nasal_ast ret_expr();
public:
uint32_t err(){return error;}
nasal_parse(nasal_err& e):nerr(e){}
void print(){root.print(0);}
void compile(const nasal_lexer&);
nasal_ast& ast(){return root;}
@ -107,7 +107,7 @@ public:
void nasal_parse::compile(const nasal_lexer& lexer)
{
tokens=lexer.get_tokens().data();
ptr=in_func=in_loop=error=0;
ptr=in_func=in_loop=0;
root={1,ast_root};
while(tokens[ptr].type!=tok_eof)
@ -119,11 +119,12 @@ void nasal_parse::compile(const nasal_lexer& lexer)
else if(need_semi_check(root.child().back()) && tokens[ptr].type!=tok_eof)
die(error_line,"expected \";\"");
}
nerr.chkerr();
}
void nasal_parse::die(uint32_t line,const std::string& info)
{
++error;
std::cout<<"[parse] line "<<line<<": "<<info<<".\n";
int col=(int)tokens[ptr].column-(int)tokens[ptr].str.length();
nerr.err("parse",line,col<0?0:col,info);
}
void nasal_parse::match(uint32_t type,const char* info)
{

View File

@ -1,6 +1,6 @@
import("lib.nas");
var filename=["main.cpp","nasal_ast.h","nasal_builtin.h","nasal_codegen.h","nasal_gc.h","nasal_import.h","nasal_lexer.h","nasal_parse.h","nasal_vm.h","nasal_dbg.h","nasal.h"];
var space=[" "," ","",""," "," "," "," "," "," "," "];
var filename=["main.cpp","nasal_err.h","nasal_ast.h","nasal_builtin.h","nasal_codegen.h","nasal_gc.h","nasal_import.h","nasal_lexer.h","nasal_parse.h","nasal_vm.h","nasal_dbg.h","nasal.h"];
var space=[" "," "," ","",""," "," "," "," "," "," "," "];
var enter_cnt=func(s)
{
var (cnt,len,enter)=(0,size(s),'\n'[0]);

View File

@ -30,7 +30,10 @@ var prt=func()
s~=elem~' ';
s~='\n';
}
system("cls");
if(os.platform()=="windows")
system("cls");
else
system("clear");
print(s);
}