225 lines
5.6 KiB
C++
225 lines
5.6 KiB
C++
#ifndef __NASAL_CODEGEN_H__
|
|
#define __NASAL_CODEGEN_H__
|
|
|
|
// unfinished
|
|
// now it can output ast but it is not byte code yet
|
|
// please wait...
|
|
class nasal_codegen
|
|
{
|
|
private:
|
|
std::vector<unsigned char> file_header;
|
|
std::vector<unsigned char> output_file;
|
|
std::vector<std::string> string_table;
|
|
int error;
|
|
void init();
|
|
void output_int(unsigned int,std::vector<unsigned char>&);
|
|
void output_short(unsigned short,std::vector<unsigned char>&);
|
|
void output_root(nasal_ast&);
|
|
unsigned int input_int(std::ifstream&);
|
|
unsigned short input_short(std::ifstream&);
|
|
void input_root(nasal_ast&,std::ifstream&);
|
|
public:
|
|
nasal_codegen();
|
|
int get_error();
|
|
void output_exec(std::string,nasal_ast&);
|
|
void load_exec(std::string,nasal_ast&);
|
|
};
|
|
|
|
nasal_codegen::nasal_codegen()
|
|
{
|
|
error=0;
|
|
string_table.clear();
|
|
return;
|
|
}
|
|
|
|
int nasal_codegen::get_error()
|
|
{
|
|
return error;
|
|
}
|
|
|
|
void nasal_codegen::init()
|
|
{
|
|
error=0;
|
|
string_table.clear();
|
|
file_header.clear();
|
|
output_file.clear();
|
|
return;
|
|
}
|
|
|
|
void nasal_codegen::output_int(unsigned int num,std::vector<unsigned char>& vec)
|
|
{
|
|
unsigned int tmp=0xff000000;
|
|
unsigned int offset=24;
|
|
for(int i=0;i<4;++i)
|
|
{
|
|
vec.push_back((unsigned char)((tmp&num)>>offset));
|
|
offset-=8;
|
|
tmp>>=8;
|
|
}
|
|
return;
|
|
}
|
|
|
|
void nasal_codegen::output_short(unsigned short num,std::vector<unsigned char>& vec)
|
|
{
|
|
vec.push_back((unsigned char)((num&0xff00)>>8));
|
|
vec.push_back((unsigned char)(num&0x00ff));
|
|
return;
|
|
}
|
|
|
|
void nasal_codegen::output_root(nasal_ast& root)
|
|
{
|
|
unsigned char type=(unsigned char)root.get_type();
|
|
output_file.push_back(type);
|
|
std::vector<nasal_ast>& ref_vec=root.get_children();
|
|
unsigned short root_children_size=ref_vec.size();
|
|
output_short(root_children_size,output_file);
|
|
if(type==ast_number || type==ast_string || type==ast_identifier || type==ast_dynamic_id || type==ast_call_hash)
|
|
{
|
|
std::string tmp=root.get_str();
|
|
if(std::find(string_table.begin(),string_table.end(),tmp)==string_table.end())
|
|
{
|
|
string_table.push_back(tmp);
|
|
output_short(string_table.size()-1,output_file);
|
|
}
|
|
else
|
|
{
|
|
for(int i=0;i<string_table.size();++i)
|
|
if(string_table[i]==tmp)
|
|
{
|
|
output_short(i,output_file);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
for(unsigned short i=0;i<root_children_size;++i)
|
|
output_root(ref_vec[i]);
|
|
return;
|
|
}
|
|
|
|
void nasal_codegen::output_exec(std::string filename,nasal_ast& root)
|
|
{
|
|
// initializing
|
|
this->init();
|
|
|
|
// put header input file_header
|
|
unsigned char header[4]={0x40,0x56,0x4b,0x21};
|
|
for(int i=0;i<4;++i)
|
|
file_header.push_back(header[i]);
|
|
|
|
// main progress,put codes into output_file
|
|
output_root(root);
|
|
|
|
// put string table into file_header
|
|
output_short(string_table.size(),file_header);
|
|
for(int i=0;i<string_table.size();++i)
|
|
{
|
|
int len=string_table[i].length();
|
|
for(int j=0;j<len;++j)
|
|
file_header.push_back((unsigned char)string_table[i][j]);
|
|
file_header.push_back(0);
|
|
}
|
|
|
|
// output to file
|
|
std::ofstream fout(filename,std::ios::binary);
|
|
if(fout.fail())
|
|
{
|
|
++error;
|
|
std::cout<<">> [code] cannot generate file \""<<filename<<"\"."<<std::endl;
|
|
fout.close();
|
|
return;
|
|
}
|
|
int size=file_header.size();
|
|
for(int i=0;i<size;++i)
|
|
fout<<file_header[i];
|
|
size=output_file.size();
|
|
for(int i=0;i<size;++i)
|
|
fout<<output_file[i];
|
|
fout.close();
|
|
return;
|
|
}
|
|
|
|
unsigned int nasal_codegen::input_int(std::ifstream& fin)
|
|
{
|
|
unsigned int number=0;
|
|
for(int i=0;i<4;++i)
|
|
{
|
|
number<<=8;
|
|
number+=(unsigned char)fin.get();
|
|
}
|
|
return number;
|
|
}
|
|
|
|
unsigned short nasal_codegen::input_short(std::ifstream& fin)
|
|
{
|
|
unsigned short number=(unsigned char)fin.get();
|
|
number=(number<<8)+(unsigned char)fin.get();
|
|
return number;
|
|
}
|
|
|
|
void nasal_codegen::input_root(nasal_ast& root,std::ifstream& fin)
|
|
{
|
|
unsigned char type=(unsigned char)fin.get();
|
|
unsigned short size=input_short(fin);
|
|
root.set_type(type);
|
|
if(type==ast_number || type==ast_string || type==ast_identifier || type==ast_dynamic_id || type==ast_call_hash)
|
|
{
|
|
std::string tmp=string_table[input_short(fin)];
|
|
root.set_str(tmp);
|
|
}
|
|
for(unsigned short i=0;i<size;++i)
|
|
{
|
|
nasal_ast new_ast;
|
|
root.add_child(new_ast);
|
|
input_root(root.get_children().back(),fin);
|
|
if(error)
|
|
return;
|
|
}
|
|
return;
|
|
}
|
|
|
|
void nasal_codegen::load_exec(std::string filename,nasal_ast& root)
|
|
{
|
|
// initializing
|
|
string_table.clear();
|
|
root.clear();
|
|
|
|
// start input
|
|
std::ifstream fin(filename,std::ios::binary);
|
|
if(fin.fail())
|
|
{
|
|
++error;
|
|
std::cout<<">> [code] cannot open file\""<<filename<<"\"."<<std::endl;
|
|
fin.close();
|
|
return;
|
|
}
|
|
|
|
// check header
|
|
unsigned char header[4]={0x40,0x56,0x4b,0x21};
|
|
for(int i=0;i<4;++i)
|
|
if((unsigned char)fin.get()!=header[i])
|
|
{
|
|
++error;
|
|
std::cout<<">> [code] \""<<filename<<"\" is not an executable file."<<std::endl;
|
|
return;
|
|
}
|
|
|
|
// input string table
|
|
unsigned short string_num=input_short(fin);
|
|
for(int i=0;i<string_num;++i)
|
|
{
|
|
std::string tmp="";
|
|
while(1)
|
|
{
|
|
unsigned char c=(unsigned char)fin.get();
|
|
if(!c || fin.eof()) break;
|
|
tmp+=c;
|
|
}
|
|
string_table.push_back(tmp);
|
|
}
|
|
|
|
// generate root
|
|
input_root(root,fin);
|
|
return;
|
|
}
|
|
|
|
#endif |