update 'import'

This commit is contained in:
Valk Richard Li 2020-10-11 05:28:27 -07:00 committed by GitHub
parent e223eff9b9
commit 939a7a62b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 263 additions and 97 deletions

View File

@ -1,3 +1,8 @@
var import=func(filename)
{
nasal_call_import(filename);
return nil;
}
var print=func(elements...)
{
nasal_call_builtin_std_cout(elements);

View File

@ -3,20 +3,19 @@
nasal_resource resource;
nasal_lexer lexer;
nasal_parse parse;
nasal_import preprocessor;
std::string command;
std::string inputfile="null";
nasal_runtime runtime;
void help()
{
std::cout<<">> [\'file\'] input a file."<<std::endl;
std::cout<<">> [cls ] clear the screen."<<std::endl;
std::cout<<">> [\"file\"] input a file."<<std::endl;
std::cout<<">> [clear ] clear the screen."<<std::endl;
std::cout<<">> [del ] clear the resource code."<<std::endl;
std::cout<<">> [lib ] add lib file."<<std::endl;
std::cout<<">> [rs ] print resource code."<<std::endl;
std::cout<<">> [lex ] turn code into tokens."<<std::endl;
std::cout<<">> [par ] turn tokens into abstract syntax tree."<<std::endl;
std::cout<<">> [ast ] check the abstract syntax tree."<<std::endl;
std::cout<<">> [del ] clear the source code."<<std::endl;
std::cout<<">> [rs ] print source code."<<std::endl;
std::cout<<">> [lex ] use lexer to turn code into tokens."<<std::endl;
std::cout<<">> [ast ] do parsing and check the abstract syntax tree."<<std::endl;
std::cout<<">> [run ] run code."<<std::endl;
std::cout<<">> [logo ] print logo of nasal ."<<std::endl;
std::cout<<">> [exit ] quit nasal interpreter."<<std::endl;
@ -38,68 +37,70 @@ void del_func()
resource.clear();
lexer.clear();
parse.clear();
inputfile="null";
std::cout<<">> [Delete] complete."<<std::endl;
return;
}
void die(std::string stage,std::string filename)
{
std::cout<<">> ["<<stage<<"] in <\""<<filename<<"\">: error(s) occurred,stop."<<std::endl;
return;
}
void lex_func()
{
lexer.scanner(resource.get_file());
if(!lexer.get_error())
lexer.print_token();
else
std::cout<<">> [lexer] error(s) occurred,stop.\n";
return;
}
void par_func()
{
lexer.scanner(resource.get_file());
if(!lexer.get_error())
if(lexer.get_error())
{
parse.set_toklist(lexer.get_token_list());
parse.main_process();
if(parse.get_error())
std::cout<<">> [parse] error(s) occurred,stop.\n";
die("lexer",inputfile);
return;
}
else
std::cout<<">> [lexer] error(s) occurred,stop.\n";
lexer.print_token();
return;
}
void ast_print()
{
lexer.scanner(resource.get_file());
if(!lexer.get_error())
if(lexer.get_error())
{
parse.set_toklist(lexer.get_token_list());
parse.main_process();
if(parse.get_error())
std::cout<<">> [parse] error(s) occurred,stop.\n";
else
parse.get_root().print_ast(0);
die("lexer",inputfile);
return;
}
else
std::cout<<">> [lexer] error(s) occurred,stop.\n";
parse.set_toklist(lexer.get_token_list());
parse.main_process();
if(parse.get_error())
{
die("parse",inputfile);
return;
}
parse.get_root().print_ast(0);
return;
}
void runtime_start()
{
lexer.scanner(resource.get_file());
if(!lexer.get_error())
if(lexer.get_error())
{
parse.set_toklist(lexer.get_token_list());
parse.main_process();
if(parse.get_error())
std::cout<<">> [parse] error(s) occurred,stop.\n";
else
{
runtime.set_root(parse.get_root());
runtime.run();
}
die("lexer",inputfile);
return;
}
else
std::cout<<">> [lexer] error(s) occurred,stop.\n";
parse.set_toklist(lexer.get_token_list());
parse.main_process();
if(parse.get_error())
{
die("parse",inputfile);
return;
}
preprocessor.preprocessing(parse.get_root());
if(preprocessor.get_error())
{
die("import",inputfile);
return;
}
runtime.set_root(preprocessor.get_root());
runtime.run();
return;
}
@ -110,7 +111,6 @@ int main()
system("chcp 65001");
system("cls");
#endif
// this curve looks really cool
logo();
#ifdef _WIN32
std::cout<<">> [system] Windows system."<<std::endl;
@ -121,9 +121,10 @@ int main()
#ifdef TARGET_OS_MAC
std::cout<<">> [system] MacOS system."<<std::endl;
#endif
std::cout<<">> Nasal interpreter ver 3.0 ."<<std::endl;
std::cout<<">> Code: https://github.com/ValKmjolnir/Nasal-Interpreter"<<std::endl;
std::cout<<">> More info: http://wiki.flightgear.org/Nasal_scripting_language"<<std::endl;
std::cout<<">> Info: http://wiki.flightgear.org/Nasal_scripting_language"<<std::endl;
std::cout<<">> Input \"help\" to get help ."<<std::endl;
while(1)
{
@ -131,7 +132,7 @@ int main()
std::cin>>command;
if(command=="help")
help();
else if(command=="cls" || command=="clear")
else if(command=="clear")
{
#ifdef _WIN32
system("cls");
@ -145,14 +146,10 @@ int main()
}
else if(command=="del")
del_func();
else if(command=="lib")
resource.load_lib();
else if(command=="rs")
resource.print_file();
else if(command=="lex")
lex_func();
else if(command=="par")
par_func();
else if(command=="ast")
ast_print();
else if(command=="run")
@ -162,7 +159,10 @@ int main()
else if(command=="exit")
break;
else
resource.input_file(command);
{
inputfile=command;
resource.input_file(inputfile);
}
}
return 0;
}

View File

@ -24,6 +24,7 @@
#include "nasal_lexer.h"
#include "nasal_ast.h"
#include "nasal_parse.h"
#include "nasal_import.h"
#include "nasal_gc.h"
#include "nasal_runtime.h"
#include "nasal_builtin.h"

View File

@ -8,7 +8,7 @@ int nasal_runtime::builtin_print(int local_scope_addr)
{
// get arguments
int vector_value_addr=in_builtin_find("elements");
if(vector_value_addr<0 || nasal_vm.gc_get(vector_value_addr).get_type()!=vm_vector)
if(vector_value_addr<0 || !in_builtin_check(vector_value_addr,vm_vector))
{
std::cout<<">> [runtime] builtin_print: cannot find values or wrong value type."<<std::endl;
++error;
@ -42,13 +42,13 @@ int nasal_runtime::builtin_append(int local_scope_addr)
{
int vector_value_addr=in_builtin_find("vector");
int elem_value_addr=in_builtin_find("elements");
if(vector_value_addr<0 || nasal_vm.gc_get(vector_value_addr).get_type()!=vm_vector)
if(vector_value_addr<0 || !in_builtin_check(vector_value_addr,vm_vector))
{
std::cout<<">> [runtime] builtin_append: cannot find values or wrong value type."<<std::endl;
++error;
return -1;
}
if(elem_value_addr<0 || nasal_vm.gc_get(elem_value_addr).get_type()!=vm_vector)
if(elem_value_addr<0 || !in_builtin_check(elem_value_addr,vm_vector))
{
std::cout<<">> [runtime] builtin_append: cannot find values or wrong value type."<<std::endl;
++error;
@ -248,7 +248,6 @@ int nasal_runtime::builtin_foutput(int local_scope_addr)
return ret_addr;
}
int nasal_runtime::builtin_split(int local_scope_addr)
{
int delimeter_value_addr=in_builtin_find("delimeter");
@ -736,8 +735,17 @@ int nasal_runtime::builtin_getkeys(int local_scope_addr)
++error;
return -1;
}
int ret_addr=nasal_vm.gc_get(hash_addr).get_hash().get_keys();
return ret_addr;
}
int nasal_runtime::builtin_import(int local_scope_addr)
{
// this function is used in preprocessing.
// this function will return nothing when running.
++error;
std::cout<<">> [runtime] cannot use import when running."<<std::endl;
int ret_addr=nasal_vm.gc_alloc();
nasal_vm.gc_get(ret_addr).set_type(vm_nil);
return ret_addr;
}
#endif

174
version3.0/nasal_import.h Normal file
View File

@ -0,0 +1,174 @@
#ifndef __NASAL_IMPORT_H__
#define __NASAL_IMPORT_H__
class nasal_import
{
private:
nasal_resource import_src;
nasal_lexer import_lex;
nasal_parse import_par;
nasal_ast import_ast;
std::vector<std::string> filename_table;
int error;
void die(std::string,std::string);
void init();
bool check_import(nasal_ast&);
bool check_exist(std::string);
void linker(nasal_ast&,nasal_ast&);
nasal_ast file_import(nasal_ast&);
nasal_ast load(nasal_ast&);
public:
nasal_import();
int get_error();
void preprocessing(nasal_ast&);
nasal_ast& get_root();
};
nasal_import::nasal_import()
{
import_src.clear();
import_lex.clear();
import_par.clear();
import_ast.clear();
filename_table.clear();
return;
}
void nasal_import::die(std::string filename,std::string error_stage)
{
++error;
std::cout<<">> [import] in <\""<<filename<<"\">: error(s) occurred in "<<error_stage<<"."<<std::endl;
return;
}
void nasal_import::init()
{
import_src.clear();
import_lex.clear();
import_par.clear();
return;
}
bool nasal_import::check_import(nasal_ast& node)
{
/*
call
id:import
call_func
string:'filename'
*/
if(node.get_type()!=ast_call)
return false;
std::vector<nasal_ast>& ref_vec=node.get_children();
if(ref_vec.size()!=2)
return false;
if(ref_vec[0].get_str()!="import")
return false;
if(ref_vec[1].get_type()!=ast_call_func)
return false;
if(ref_vec[1].get_children().size()!=1 || ref_vec[1].get_children()[0].get_type()!=ast_string)
return false;
return true;
}
bool nasal_import::check_exist(std::string filename)
{
int size=filename_table.size();
for(int i=0;i<size;++i)
if(filename==filename_table[i])
return true;
filename_table.push_back(filename);
return false;
}
void nasal_import::linker(nasal_ast& root,nasal_ast& add_root)
{
std::vector<nasal_ast>& ref_vec=add_root.get_children();
int size=ref_vec.size();
for(int i=0;i<size;++i)
root.add_child(ref_vec[i]);
return;
}
nasal_ast nasal_import::file_import(nasal_ast& node)
{
// initializing
nasal_ast tmp;
tmp.set_line(0);
tmp.set_type(ast_root);
init();
// get filename and set node to ast_null
std::string filename=node.get_children()[1].get_children()[0].get_str();
node.clear();
node.set_type(ast_null);
// avoid infinite loading loop
if(check_exist(filename))
return tmp;
// start importing...
if(!import_src.input_file(filename))
{
die(filename,"resource");
return tmp;
}
import_lex.scanner(import_src.get_file());
if(import_lex.get_error())
{
die(filename,"lexer");
return tmp;
}
import_par.set_toklist(import_lex.get_token_list());
import_par.main_process();
if(import_par.get_error())
{
die(filename,"parser");
return tmp;
}
tmp=import_par.get_root();
// check if tmp has 'import'
return load(tmp);
}
nasal_ast nasal_import::load(nasal_ast& root)
{
nasal_ast new_root;
new_root.set_line(0);
new_root.set_type(ast_root);
std::vector<nasal_ast>& ref_vec=root.get_children();
int size=ref_vec.size();
for(int i=0;i<size;++i)
{
if(check_import(ref_vec[i]))
{
nasal_ast tmp=file_import(ref_vec[i]);
// add tmp to the back of new_root
linker(new_root,tmp);
}
}
// add root to the back of new_root
linker(new_root,root);
return new_root;
}
void nasal_import::preprocessing(nasal_ast& root)
{
// initializing
error=0;
filename_table.clear();
import_ast.clear();
// scan root and import files,then generate a new ast and return to import_ast
import_ast=load(root);
return;
}
nasal_ast& nasal_import::get_root()
{
return import_ast;
}
int nasal_import::get_error()
{
return error;
}
#endif

View File

@ -113,11 +113,13 @@ std::string nasal_lexer::number_gen(std::vector<char>& res,int& ptr,int& line)
{
int res_size=res.size();
bool scientific_notation=false;// numbers like 1e8 are scientific_notation
bool is_hex=(ptr<res_size && res[ptr]=='0' && ptr+1<res_size && res[ptr+1]=='x');
bool is_oct=(ptr<res_size && res[ptr]=='0' && ptr+1<res_size && res[ptr+1]=='o');
std::string token_str="";
while(ptr<res_size && IS_NUMBER_BODY(res[ptr]))
{
token_str+=res[ptr];
if(res[ptr]=='e' || res[ptr]=='E')
if((res[ptr]=='e' || res[ptr]=='E') && !is_hex && !is_oct)
{
scientific_notation=true;
++ptr;
@ -298,7 +300,7 @@ void nasal_lexer::scanner(std::vector<char>& res)
else if(IS_NOTE_HEAD(res[ptr]))
{
// avoid note
while(ptr<res_size && res[ptr++]!='\n');
while(ptr<res_size && res[ptr]!='\n') ++ptr;
// after this process ptr will point to a '\n'
// don't ++ptr then the counter for line can work correctly
}
@ -309,7 +311,6 @@ void nasal_lexer::scanner(std::vector<char>& res)
++ptr;
}
}
std::cout<<">> [lexer] complete scanning. "<<error<<" error(s)."<<std::endl;
return;
}

View File

@ -146,7 +146,6 @@ void nasal_parse::main_process()
}
}
}
std::cout<<">> [parse] complete generation. "<<error<<" error(s)."<<std::endl;
return;
}

View File

@ -1,45 +1,26 @@
#ifndef __NASAL_RESOURCE_H__
#define __NASAL_RESOURCE_H__
/* filenames of lib files */
#ifndef LIB_FILE_NUM
#define LIB_FILE_NUM 11
const std::string lib_filename[LIB_FILE_NUM]=
{
"lib/base.nas",
"lib/bits.nas",
"lib/io.nas",
"lib/math.nas",
"lib/readline.nas",
"lib/regex.nas",
"lib/sqlite.nas",
"lib/system.nas",
"lib/thread.nas",
"lib/unix.nas",
"lib/utf8.nas"
};
#endif
class nasal_resource
{
private:
std::vector<char> res;
public:
void input_file(std::string);
void load_lib();
void clear();
void print_file();
bool input_file(std::string);
void clear();
void print_file();
std::vector<char>& get_file();
};
void nasal_resource::input_file(std::string filename)
bool nasal_resource::input_file(std::string filename)
{
res.clear();
std::ifstream fin(filename,std::ios::binary);
if(fin.fail())
{
std::cout<<">> [resource] cannot open file \'"<<filename<<"\'."<<std::endl;
std::cout<<">> [resource] cannot open file \""<<filename<<"\"."<<std::endl;
fin.close();
return;
return false;
}
while(!fin.eof())
{
@ -48,14 +29,7 @@ void nasal_resource::input_file(std::string filename)
res.push_back(c);
}
fin.close();
return;
}
void nasal_resource::load_lib()
{
for(int i=0;i<LIB_FILE_NUM;++i)
this->input_file(lib_filename[i]);
return;
return true;
}
void nasal_resource::clear()

View File

@ -99,6 +99,7 @@ private:
int builtin_contains(int);
int builtin_delete(int);
int builtin_getkeys(int);
int builtin_import(int);
void load_builtin_function();
public:
nasal_runtime();
@ -163,6 +164,7 @@ void nasal_runtime::load_builtin_function()
{"nasal_call_builtin_contains", nasal_runtime::builtin_contains},
{"nasal_call_builtin_delete", nasal_runtime::builtin_delete},
{"nasal_call_builtin_get_keys", nasal_runtime::builtin_getkeys},
{"nasal_call_import", nasal_runtime::builtin_import},
{"", NULL}
};
for(int i=0;builtin_func_table[i].func_pointer;++i)
@ -271,6 +273,7 @@ int nasal_runtime::main_progress()
case ast_while:case ast_for:case ast_forindex:case ast_foreach:
ret_state=loop_progress(root.get_children()[i],-1,false);break;
case ast_nil:case ast_number:case ast_string:case ast_function:break;
case ast_identifier:
case ast_vector:case ast_hash:
case ast_call:
case ast_equal:case ast_add_equal:case ast_sub_equal:case ast_mult_equal:case ast_div_equal:case ast_link_equal:
@ -325,6 +328,7 @@ int nasal_runtime::block_progress(nasal_ast& node,int local_scope_addr,bool allo
case ast_while:case ast_for:case ast_forindex:case ast_foreach:
ret_state=loop_progress(tmp_node,local_scope_addr,allow_return);break;
case ast_nil:case ast_number:case ast_string:case ast_function:break;
case ast_identifier:
case ast_vector:case ast_hash:
case ast_call:
case ast_equal:case ast_add_equal:case ast_sub_equal:case ast_mult_equal:case ast_div_equal:case ast_link_equal: