Update lexer and parser
This commit is contained in:
parent
a136f3993d
commit
8a43e69c2c
|
@ -0,0 +1,24 @@
|
|||
var e=e(e,e,e);
|
||||
e+=e();
|
||||
e+=e(e);
|
||||
e+=e(e,e);
|
||||
var e=e[0];
|
||||
var e=func()
|
||||
{
|
||||
var e=e;
|
||||
var e=[];
|
||||
}
|
||||
var e=func(e...)
|
||||
{
|
||||
e+=1;
|
||||
}
|
||||
var e=func(e)
|
||||
{
|
||||
e-=2;
|
||||
}
|
||||
var e=func(e,e,e)
|
||||
{
|
||||
e~="null_end_of_str";
|
||||
var e=e.e.e.e.ee.e;
|
||||
e();
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
# Road check and auto pilot(??) by ValKmjolnir
|
||||
|
||||
var position_change = func(position_val,value){
|
||||
if(position_val+value>180)
|
||||
position_val += value-360;
|
||||
else if(position_val+value<-180)
|
||||
position_val += value+360;
|
||||
else
|
||||
position_val += value;
|
||||
return position_val;
|
||||
}
|
||||
var road_check_func = func(){
|
||||
|
||||
var lat = props.getNode("/position/latitude-deg",1).getValue();
|
||||
var lon = props.getNode("/position/longitude-deg",1).getValue();
|
||||
var position_info = geodinfo(lat,lon);
|
||||
var position_names = position_info[1].names;
|
||||
# the friction_factor of freeway runway and road is 1
|
||||
|
||||
if((position_names[0]=="Freeway") or (position_names[0]=="Road"))
|
||||
{
|
||||
var car_heading = 0;
|
||||
var lat_change = 0;
|
||||
var lon_change = 0;
|
||||
var left_range = 0;
|
||||
var right_range = 0;
|
||||
|
||||
for(var i=0;i>-0.00005;i-=0.000001)
|
||||
{
|
||||
car_heading = props.getNode("/orientation/heading-deg",1).getValue();
|
||||
lat_change = math.sin(math.pi*car_heading/180);
|
||||
lon_change = -math.cos(math.pi*car_heading/180);
|
||||
lat = props.getNode("/position/latitude-deg",1).getValue()+0.0001*math.cos(math.pi*car_heading/180);
|
||||
lon = props.getNode("/position/longitude-deg",1).getValue()+0.0001*math.sin(math.pi*car_heading/180);
|
||||
var other_position_info = geodinfo(position_change(lat,i*lat_change),position_change(lon,i*lon_change));
|
||||
var other_names = other_position_info[1].names;
|
||||
if((other_names[0]=="Freeway") or (other_names[0]=="Road"))
|
||||
right_range += 1;
|
||||
else
|
||||
break;
|
||||
}
|
||||
for(var i=0;i<0.00005;i+=0.000001)
|
||||
{
|
||||
car_heading = props.getNode("/orientation/heading-deg",1).getValue();
|
||||
lat_change = math.sin(math.pi*car_heading/180);
|
||||
lon_change = -math.cos(math.pi*car_heading/180);
|
||||
lat = props.getNode("/position/latitude-deg",1).getValue()+0.0001*math.cos(math.pi*car_heading/180);
|
||||
lon = props.getNode("/position/longitude-deg",1).getValue()+0.0001*math.sin(math.pi*car_heading/180);
|
||||
var other_position_info = geodinfo(position_change(lat,i*lat_change),position_change(lon,i*lon_change));
|
||||
var other_names = other_position_info[1].names;
|
||||
if((other_names[0]=="Freeway") or (other_names[0]=="Road"))
|
||||
left_range+=1;
|
||||
else
|
||||
break;
|
||||
}
|
||||
#if(left_range>right_range)
|
||||
#{
|
||||
# setprop("/controls/flight/rudder",-(right_range-left_range)*(right_range-left_range)/10000);
|
||||
# print("right ",right_range);
|
||||
#}
|
||||
#else if(left_range<right_range)
|
||||
#{
|
||||
# setprop("/controls/flight/rudder",(right_range-left_range)*(right_range-left_range)/10000);
|
||||
# print("left ",left_range);
|
||||
#}
|
||||
#else
|
||||
# setprop("/controls/flight/rudder",0);
|
||||
props.getNode("/controls/flight/rudder",1).setValue((right_range-left_range)/200);
|
||||
}
|
||||
};
|
||||
var road_check_timer = maketimer(0.1,road_check_func);
|
||||
var toggle_auto_pilot = func(){
|
||||
if(!road_check_timer.isRunning)
|
||||
{
|
||||
road_check_timer.start();
|
||||
props.getNode("/sim/messages/copilot",1).setValue("ze dong sheng teaan see tong yee tse yung. Auto Sheng Teaan System Activated!");
|
||||
}
|
||||
else
|
||||
{
|
||||
road_check_timer.stop();
|
||||
props.getNode("/sim/messages/copilot",1).setValue("ze dong sheng teaan see tong yee guan bee. Auto Sheng Teaan System is off.");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
#include "nasal_lexer.h"
|
||||
#include "nasal_parser.h"
|
||||
#include <iostream>
|
||||
#include <cstring>
|
||||
|
||||
int main()
|
||||
{
|
||||
resource_programme_process prog;
|
||||
nasal_lexer lex;
|
||||
nasal_parser pas;
|
||||
std::string command;
|
||||
std::cout<<">> nasal script interpreter by ValKmjolnir"<<std::endl;
|
||||
std::cout<<">> input \"help\" to find help."<<std::endl;
|
||||
std::cout<<">> Be careful: this interpreter uses strict methods to check if there's an error."<<std::endl;
|
||||
std::cout<<" Always add \";\" after each statement (except loop and if-else)."<<std::endl;
|
||||
while(1)
|
||||
{
|
||||
std::cout<<">> ";
|
||||
std::getline(std::cin,command);
|
||||
if(command=="help")
|
||||
{
|
||||
std::cout<<">> nasal script interpreter by ValKmjolnir"<<std::endl;
|
||||
std::cout<<">> 1. |input file name to load the file."<<std::endl;
|
||||
std::cout<<">> 2. \"cls\" |clear the screen."<<std::endl;
|
||||
std::cout<<">> 3. \"exit\" |shut down the interpreter."<<std::endl;
|
||||
std::cout<<">> 4. \"lexer\" |run and show the lexer. (-lexer)"<<std::endl;
|
||||
std::cout<<">> 5. \"parser\"|run parser. (-parser)"<<std::endl;
|
||||
std::cout<<">> 6. \"del\" |delete all elements in stack."<<std::endl;
|
||||
std::cout<<">> 7. \"run\" |run the programme in stack. (-lexer -parser)"<<std::endl;
|
||||
std::cout<<">> 8. \"rs\" |check the source program."<<std::endl;
|
||||
}
|
||||
else if(command=="cls")
|
||||
{
|
||||
system("cls");
|
||||
//windows system("cls);
|
||||
//linux system("clear");
|
||||
//macOS system("clear");
|
||||
}
|
||||
else if(command=="rs")
|
||||
prog.print_file();
|
||||
else if(command=="exit")
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if(command=="lexer")
|
||||
{
|
||||
lex.lexer_process(prog.use_file());
|
||||
lex.print_lexer();
|
||||
}
|
||||
else if(command=="del")
|
||||
{
|
||||
prog.del_file();
|
||||
std::cout<<">>[Delete] Complete."<<std::endl;
|
||||
}
|
||||
else if(command=="parser")
|
||||
{
|
||||
pas.parse_process(lex.return_list(),true);
|
||||
}
|
||||
else if(command=="run")
|
||||
{
|
||||
lex.lexer_process(prog.use_file());
|
||||
pas.parse_process(lex.return_list(),false);
|
||||
}
|
||||
else
|
||||
prog.input_file(command);
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,412 @@
|
|||
#ifndef __NASAL_LEXER_H__
|
||||
#define __NASAL_LEXER_H__
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <list>
|
||||
#include <cstring>
|
||||
|
||||
#define OPERATOR 1 // operator
|
||||
#define IDENTIFIER 2 // id
|
||||
#define NUMBER 3 // number
|
||||
#define RESERVEWORD 4 // reserve word
|
||||
#define STRING 5 // string
|
||||
#define CHAR 6 // char
|
||||
#define CALL_LIST 7 // id[
|
||||
#define CALL_FUNC 8 // id(
|
||||
#define FUNC_HEAD 9 // func(
|
||||
#define DYNAMIC_ID 10 // id...
|
||||
#define FAIL -1 //fail
|
||||
#define SCANEND -2 //complete scanning
|
||||
#define ERRORFOUND -3 //error occurred
|
||||
|
||||
std::string reserve_word[15]=
|
||||
{
|
||||
"for","foreach","forindex","while",
|
||||
"var","func","break","continue","return",
|
||||
"if","else","elsif","nil","and","or"
|
||||
};
|
||||
|
||||
int isReserveWord(std::string &p)
|
||||
{
|
||||
for(int i=0;i<15;++i)
|
||||
if(reserve_word[i]==p)
|
||||
return i+1;
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
bool isLetter(char t)
|
||||
{
|
||||
return (('a'<=t) && (t<='z') || ('A'<=t) && (t<='Z'));
|
||||
}
|
||||
|
||||
bool isNumber(char t)
|
||||
{
|
||||
return (('0'<=t) && (t<='9'));
|
||||
}
|
||||
|
||||
bool isHex(char t)
|
||||
{
|
||||
return ((('0'<=t) && (t<='9')) || (('a'<=t) && (t<='f')));
|
||||
}
|
||||
|
||||
bool isOct(char t)
|
||||
{
|
||||
return (('0'<=t) && (t<='7'));
|
||||
}
|
||||
|
||||
class resource_programme_process
|
||||
{
|
||||
private:
|
||||
char *resource;
|
||||
public:
|
||||
resource_programme_process()
|
||||
{
|
||||
resource=NULL;
|
||||
resource=new char[16777216];
|
||||
}
|
||||
~resource_programme_process()
|
||||
{
|
||||
if(resource)
|
||||
delete []resource;
|
||||
}
|
||||
char* use_file()
|
||||
{
|
||||
return resource;
|
||||
}
|
||||
void input_file(std::string& filename)
|
||||
{
|
||||
std::ifstream fin(filename);
|
||||
if(fin.fail())
|
||||
{
|
||||
std::cout<<">>[Error] Cannot load file: "<<filename<<" ."<<std::endl;
|
||||
fin.close();
|
||||
return;
|
||||
}
|
||||
memset(resource,0,sizeof(char));
|
||||
int i=0;
|
||||
bool findnote=false;// to find the note with # at the head of line.
|
||||
while(!fin.eof())
|
||||
{
|
||||
resource[i]=fin.get();
|
||||
if(resource[i]=='\n')
|
||||
findnote=false;
|
||||
//when meeting '\n' the findnote is set to false then the next statement can be executed.
|
||||
if(resource[i]!='#' && !findnote)
|
||||
++i;
|
||||
else if(resource[i]=='#')
|
||||
findnote=true;
|
||||
if(fin.eof())
|
||||
break;
|
||||
}
|
||||
resource[i]='\0';
|
||||
fin.close();
|
||||
return;
|
||||
}
|
||||
void print_file()
|
||||
{
|
||||
if(!resource[0])
|
||||
{
|
||||
std::cout<<"0 null"<<std::endl;
|
||||
return;
|
||||
}
|
||||
int line=1;
|
||||
std::cout<<line<<" ";
|
||||
for(int i=0;i<16777216;++i)
|
||||
{
|
||||
if(!resource[i])
|
||||
break;
|
||||
std::cout<<resource[i];
|
||||
if(resource[i]=='\n')
|
||||
{
|
||||
++line;
|
||||
std::cout<<line<<" ";
|
||||
}
|
||||
}
|
||||
std::cout<<std::endl;
|
||||
return;
|
||||
}
|
||||
void del_file()
|
||||
{
|
||||
memset(resource,0,sizeof(char));
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
struct token
|
||||
{
|
||||
int line;
|
||||
int type;
|
||||
std::string content;
|
||||
};
|
||||
|
||||
class nasal_lexer
|
||||
{
|
||||
private:
|
||||
std::list<token> lexer;
|
||||
public:
|
||||
void scanner(int &syn,const char* source,std::string &__token,int &ptr,int &line)
|
||||
{
|
||||
char temp;
|
||||
temp=source[ptr];
|
||||
while(temp==' ' || temp=='\n' || temp=='\t' || temp=='\r' || temp<0 || temp>127)
|
||||
{
|
||||
++ptr;
|
||||
if(temp=='\n')
|
||||
++line;
|
||||
temp=source[ptr];
|
||||
}
|
||||
__token="";
|
||||
if(isLetter(temp) || temp=='_')
|
||||
{
|
||||
__token+=temp;
|
||||
++ptr;
|
||||
temp=source[ptr];
|
||||
while(isLetter(temp) || isNumber(temp) || temp=='_')
|
||||
{
|
||||
__token+=temp;
|
||||
++ptr;
|
||||
temp=source[ptr];
|
||||
}
|
||||
syn=isReserveWord(__token);
|
||||
if(syn==FAIL)
|
||||
syn=IDENTIFIER;
|
||||
else
|
||||
syn=RESERVEWORD;
|
||||
if((syn==IDENTIFIER) && ((source[ptr]=='(') || (source[ptr]=='[') || (source[ptr]=='.' && source[ptr+1]=='.' && source[ptr+2]=='.')))
|
||||
{
|
||||
__token+=source[ptr];
|
||||
if(source[ptr]=='(')
|
||||
syn=CALL_FUNC;
|
||||
else if(source[ptr]=='[')
|
||||
syn=CALL_LIST;
|
||||
else if(source[ptr]=='.' && source[ptr+1]=='.' && source[ptr+2]=='.')
|
||||
{
|
||||
__token+="..";
|
||||
syn=DYNAMIC_ID;
|
||||
ptr+=2;
|
||||
}
|
||||
++ptr;
|
||||
}
|
||||
else if((syn==RESERVEWORD) && (__token=="func") && (source[ptr]=='('))
|
||||
{
|
||||
__token+=source[ptr];
|
||||
syn=FUNC_HEAD;
|
||||
++ptr;
|
||||
}
|
||||
}
|
||||
else if(isNumber(temp))
|
||||
{
|
||||
if((source[ptr]=='0') && (source[ptr+1]=='x'))
|
||||
{
|
||||
__token+=source[ptr];
|
||||
__token+=source[ptr+1];
|
||||
ptr+=2;
|
||||
temp=source[ptr];
|
||||
while(isNumber(temp) || isHex(temp))
|
||||
{
|
||||
__token+=temp;
|
||||
++ptr;
|
||||
temp=source[ptr];
|
||||
}
|
||||
}
|
||||
else if((source[ptr]=='0') && (source[ptr+1]=='o'))
|
||||
{
|
||||
__token+=source[ptr];
|
||||
__token+=source[ptr+1];
|
||||
ptr+=2;
|
||||
temp=source[ptr];
|
||||
while(isNumber(temp) || isOct(temp))
|
||||
{
|
||||
__token+=temp;
|
||||
++ptr;
|
||||
temp=source[ptr];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int PointCnt=0;
|
||||
while(isNumber(temp))
|
||||
{
|
||||
__token+=temp;
|
||||
++ptr;
|
||||
temp=source[ptr];
|
||||
if(temp=='.' && !PointCnt)
|
||||
{
|
||||
++PointCnt;
|
||||
__token+=temp;
|
||||
++ptr;
|
||||
temp=source[ptr];
|
||||
}
|
||||
}
|
||||
}
|
||||
syn=NUMBER;
|
||||
}
|
||||
else if(temp=='(' || temp==')' || temp=='[' || temp==']' || temp=='{' ||
|
||||
temp=='}' || temp==',' || temp==';' || temp=='|' || temp==':' ||
|
||||
temp=='?' || temp=='.' || temp=='`' || temp=='&'||
|
||||
temp=='%' || temp=='$' || temp=='^')
|
||||
{
|
||||
__token+=temp;
|
||||
++ptr;
|
||||
syn=OPERATOR;
|
||||
}
|
||||
else if(temp=='\'')
|
||||
{
|
||||
__token+=temp;
|
||||
++ptr;
|
||||
temp=source[ptr];
|
||||
__token+=temp;
|
||||
++ptr;
|
||||
temp=source[ptr];
|
||||
__token+=temp;
|
||||
++ptr;
|
||||
if(temp!='\'')
|
||||
std::cout<<">>[Lexer] Abnormal char type detected: "<<__token<<" ."<<std::endl;
|
||||
syn=CHAR;
|
||||
}
|
||||
else if(temp=='=' || temp=='+' || temp=='-' || temp=='*' || temp=='!' || temp=='/' || temp=='<' || temp=='>' || temp=='~')
|
||||
{
|
||||
syn=OPERATOR;
|
||||
__token+=temp;
|
||||
++ptr;
|
||||
temp=source[ptr];
|
||||
if(temp=='=')
|
||||
{
|
||||
__token+=temp;
|
||||
++ptr;
|
||||
}
|
||||
}
|
||||
else if(temp=='\\')
|
||||
{
|
||||
syn=OPERATOR;
|
||||
__token+=temp;
|
||||
++ptr;
|
||||
temp=source[ptr];
|
||||
if(temp=='=' || temp=='n' || temp=='t' || temp=='r' || temp=='\\' || temp=='\'' || temp=='\"')
|
||||
{
|
||||
__token+=temp;
|
||||
++ptr;
|
||||
}
|
||||
}
|
||||
else if(temp=='\"')
|
||||
{
|
||||
syn=STRING;
|
||||
__token+=temp;
|
||||
++ptr;
|
||||
temp=source[ptr];
|
||||
while(temp!='\"')
|
||||
{
|
||||
if(temp=='\\')
|
||||
{
|
||||
__token+=temp;
|
||||
|
||||
++ptr;
|
||||
temp=source[ptr];
|
||||
__token+=temp;
|
||||
|
||||
++ptr;
|
||||
temp=source[ptr];
|
||||
}
|
||||
else
|
||||
{
|
||||
__token+=temp;
|
||||
++ptr;
|
||||
temp=source[ptr];
|
||||
}
|
||||
if(temp==0 || temp=='\n')
|
||||
break;
|
||||
}
|
||||
//add the last char \"
|
||||
if(temp=='\"')
|
||||
{
|
||||
__token+=temp;
|
||||
++ptr;
|
||||
}
|
||||
else
|
||||
__token+=" __missing_end_of_string";
|
||||
}
|
||||
else if(temp==0)
|
||||
{
|
||||
syn=SCANEND;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
syn=FAIL;
|
||||
std::cout<<">>[Error] Unexpected error occurred: "<<temp<<std::endl;
|
||||
system("pause");
|
||||
++ptr;
|
||||
return;
|
||||
}
|
||||
if(__token=="")
|
||||
{
|
||||
syn=ERRORFOUND;
|
||||
std::cout<<">>[Error] Cannot identify "<<std::endl;
|
||||
}
|
||||
return;
|
||||
}
|
||||
void lexer_process(const char *source)
|
||||
{
|
||||
std::cout<<">>[Lexer] max size: "<<lexer.max_size()<<" ."<<std::endl;
|
||||
lexer.clear();
|
||||
int syn=0;//token type
|
||||
int ptr=0;//pointer to one char in ResourcePrograme
|
||||
int line=1;
|
||||
std::string __token;
|
||||
token temp;
|
||||
while(syn!=SCANEND && syn!=ERRORFOUND)
|
||||
{
|
||||
scanner(syn,source,__token,ptr,line);
|
||||
if(syn>0)//all Syn type is larger than zero
|
||||
{
|
||||
temp.line=line;
|
||||
temp.type=syn;
|
||||
temp.content=__token;
|
||||
lexer.push_back(temp);
|
||||
}
|
||||
}
|
||||
std::cout<<">>[Lexer] Complete scanning."<<std::endl;
|
||||
return;
|
||||
}
|
||||
void print_lexer()
|
||||
{
|
||||
token temp;
|
||||
for(std::list<token>::iterator i=lexer.begin();i!=lexer.end();++i)
|
||||
{
|
||||
temp=*i;
|
||||
std::cout<<"line "<<temp.line<<": ";
|
||||
if(temp.type==OPERATOR)
|
||||
std::cout<<"( Operator | ";
|
||||
else if(temp.type==IDENTIFIER)
|
||||
std::cout<<"( Identifier | ";
|
||||
else if(temp.type==NUMBER)
|
||||
std::cout<<"( Number | ";
|
||||
else if(temp.type==RESERVEWORD)
|
||||
std::cout<<"( ReserveWord | ";
|
||||
else if(temp.type==STRING)
|
||||
std::cout<<"( String | ";
|
||||
else if(temp.type==CHAR)
|
||||
std::cout<<"( Char | ";
|
||||
else if(temp.type==CALL_LIST)
|
||||
std::cout<<"( Call list head | ";
|
||||
else if(temp.type==CALL_FUNC)
|
||||
std::cout<<"( Call func head | ";
|
||||
else if(temp.type==FUNC_HEAD)
|
||||
std::cout<<"( Func head | ";
|
||||
else if(temp.type==DYNAMIC_ID)
|
||||
std::cout<<"( Identifier | ";
|
||||
std::cout<<temp.content<<" )"<<std::endl;
|
||||
}
|
||||
return;
|
||||
}
|
||||
std::list<token>& return_list()
|
||||
{
|
||||
return lexer;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,721 @@
|
|||
#ifndef __NASAL_PARSER_H__
|
||||
#define __NASAL_PARSER_H__
|
||||
|
||||
#include <stack>
|
||||
|
||||
enum token_type
|
||||
{
|
||||
__stack_end=1,
|
||||
__equal,// =
|
||||
__cmp_equal,// ==
|
||||
__cmp_not_equal,// !=
|
||||
__cmp_less,__cmp_less_or_equal,// < <=
|
||||
__cmp_more,__cmp_more_or_equal,// > >=
|
||||
__and_operator,__or_operator,__nor_operator,// and or !
|
||||
__add_operator,__sub_operator,__mul_operator,__div_operator,__link_operator,// + - * / ~
|
||||
__add_equal,__sub_equal,__mul_equal,__div_equal,__link_equal,// += -= *= /= ~=
|
||||
__left_brace,__right_brace,// {}
|
||||
__left_bracket,__right_bracket,// []
|
||||
__left_curve,__right_curve,// ()
|
||||
__semi,// ;
|
||||
__comma,// ,
|
||||
__colon,// :
|
||||
__dot,// .
|
||||
__var,
|
||||
__func,
|
||||
__id,__dynamic_id,
|
||||
__return,
|
||||
__if,__elsif,__else,
|
||||
__continue,__break,__for,__forindex,__foreach,__while,
|
||||
__call_list_head,__call_func_head,__func_head,
|
||||
//end of operators & reserve words
|
||||
__scalar,__data_list,
|
||||
__number,__string,__char,
|
||||
__list,
|
||||
__hash,
|
||||
__hash_member,
|
||||
__identifier,
|
||||
__statement,
|
||||
__function,
|
||||
__call_function,
|
||||
__call_list,
|
||||
__call_hash,
|
||||
__definition,
|
||||
__assignment,
|
||||
__calculation,
|
||||
__loop,
|
||||
__choose,
|
||||
__program
|
||||
};
|
||||
|
||||
const int max_len=10;
|
||||
struct cmp_seq
|
||||
{
|
||||
int tokens[max_len];
|
||||
int res;
|
||||
};
|
||||
// must put in a reverse way
|
||||
cmp_seq par[]=
|
||||
{
|
||||
{{__program,__statement}, __program},
|
||||
{{__semi,__semi}, __semi},
|
||||
|
||||
{{__id,__dot,__id}, __call_hash},
|
||||
{{__call_hash,__dot,__id}, __call_hash},
|
||||
|
||||
{{__right_brace,__call_function,__semi}, __right_brace},
|
||||
{{__semi,__call_function,__semi}, __semi},
|
||||
|
||||
{{__right_curve,__data_list,__call_func_head}, __call_function},
|
||||
{{__right_curve,__id,__call_func_head}, __call_function},
|
||||
{{__right_curve,__call_func_head}, __call_function},
|
||||
|
||||
{{__right_brace,__left_brace,__right_curve,__data_list,__func_head}, __function},
|
||||
{{__right_brace,__left_brace,__right_curve,__id,__func_head}, __function},
|
||||
{{__right_brace,__left_brace,__right_curve,__dynamic_id,__func_head}, __function},
|
||||
{{__right_brace,__left_brace,__right_curve,__func_head}, __function},
|
||||
|
||||
{{__right_brace,__statement,__left_brace,__right_curve,__data_list,__func_head}, __function},
|
||||
{{__right_brace,__statement,__left_brace,__right_curve,__id,__func_head}, __function},
|
||||
{{__right_brace,__statement,__left_brace,__right_curve,__dynamic_id,__func_head}, __function},
|
||||
{{__right_brace,__statement,__left_brace,__right_curve,__func_head}, __function},
|
||||
|
||||
{{__right_bracket,__number,__call_list_head}, __call_list},
|
||||
|
||||
{{__id,__comma,__id}, __data_list},
|
||||
{{__data_list,__comma,__id}, __data_list},
|
||||
|
||||
{{__calculation,__add_operator,__calculation}, __calculation},
|
||||
{{__calculation,__add_operator,__id}, __calculation},
|
||||
{{__id,__add_operator,__calculation}, __calculation},
|
||||
{{__id,__add_operator,__id}, __calculation},
|
||||
|
||||
{{__calculation,__sub_operator,__calculation}, __calculation},
|
||||
{{__calculation,__sub_operator,__id}, __calculation},
|
||||
{{__id,__sub_operator,__calculation}, __calculation},
|
||||
{{__id,__sub_operator,__id}, __calculation},
|
||||
|
||||
{{__calculation,__mul_operator,__calculation}, __calculation},
|
||||
{{__calculation,__mul_operator,__id}, __calculation},
|
||||
{{__id,__mul_operator,__calculation}, __calculation},
|
||||
{{__id,__mul_operator,__id}, __calculation},
|
||||
|
||||
{{__calculation,__div_operator,__calculation}, __calculation},
|
||||
{{__calculation,__div_operator,__id}, __calculation},
|
||||
{{__id,__div_operator,__calculation}, __calculation},
|
||||
{{__id,__div_operator,__id}, __calculation},
|
||||
|
||||
{{__calculation,__link_operator,__calculation}, __calculation},
|
||||
{{__calculation,__link_operator,__id}, __calculation},
|
||||
{{__id,__link_operator,__calculation}, __calculation},
|
||||
{{__id,__link_operator,__id}, __calculation},
|
||||
|
||||
{{__right_curve,__id,__left_curve}, __calculation},
|
||||
{{__right_curve,__calculation,__left_curve}, __calculation},
|
||||
|
||||
{{__semi,__calculation,__equal,__id,__var}, __definition},
|
||||
{{__semi,__number,__equal,__id,__var}, __definition},
|
||||
{{__semi,__string,__equal,__id,__var}, __definition},
|
||||
{{__semi,__id,__equal,__id,__var}, __definition},
|
||||
{{__semi,__char,__equal,__id,__var}, __definition},
|
||||
{{__semi,__right_brace,__left_brace,__equal,__id,__var}, __definition},
|
||||
{{__semi,__right_bracket,__left_bracket,__equal,__id,__var}, __definition},
|
||||
{{__semi,__call_function,__equal,__id,__var}, __definition},
|
||||
{{__semi,__call_list,__equal,__id,__var}, __definition},
|
||||
{{__function,__equal,__id,__var}, __definition},
|
||||
{{__semi,__function,__equal,__id,__var}, __definition},
|
||||
{{__semi,__call_hash,__equal,__id,__var}, __definition},
|
||||
|
||||
{{__semi,__calculation,__add_equal,__id}, __assignment},
|
||||
{{__semi,__number,__add_equal,__id}, __assignment},
|
||||
{{__semi,__string,__add_equal,__id}, __assignment},
|
||||
{{__semi,__id,__add_equal,__id}, __assignment},
|
||||
{{__semi,__char,__add_equal,__id}, __assignment},
|
||||
{{__semi,__call_function,__add_equal,__id}, __assignment},
|
||||
{{__semi,__call_list,__add_equal,__id}, __assignment},
|
||||
{{__semi,__call_hash,__add_equal,__id}, __assignment},
|
||||
|
||||
{{__semi,__calculation,__sub_equal,__id}, __assignment},
|
||||
{{__semi,__number,__sub_equal,__id}, __assignment},
|
||||
{{__semi,__string,__sub_equal,__id}, __assignment},
|
||||
{{__semi,__id,__sub_equal,__id}, __assignment},
|
||||
{{__semi,__char,__sub_equal,__id}, __assignment},
|
||||
{{__semi,__call_function,__sub_equal,__id}, __assignment},
|
||||
{{__semi,__call_list,__sub_equal,__id}, __assignment},
|
||||
{{__semi,__call_hash,__sub_equal,__id}, __assignment},
|
||||
|
||||
{{__semi,__calculation,__mul_equal,__id}, __assignment},
|
||||
{{__semi,__number,__mul_equal,__id}, __assignment},
|
||||
{{__semi,__string,__mul_equal,__id}, __assignment},
|
||||
{{__semi,__id,__mul_equal,__id}, __assignment},
|
||||
{{__semi,__char,__mul_equal,__id}, __assignment},
|
||||
{{__semi,__call_function,__mul_equal,__id}, __assignment},
|
||||
{{__semi,__call_list,__mul_equal,__id}, __assignment},
|
||||
{{__semi,__call_hash,__mul_equal,__id}, __assignment},
|
||||
|
||||
{{__semi,__calculation,__div_equal,__id}, __assignment},
|
||||
{{__semi,__number,__div_equal,__id}, __assignment},
|
||||
{{__semi,__string,__div_equal,__id}, __assignment},
|
||||
{{__semi,__id,__div_equal,__id}, __assignment},
|
||||
{{__semi,__char,__div_equal,__id}, __assignment},
|
||||
{{__semi,__call_function,__div_equal,__id}, __assignment},
|
||||
{{__semi,__call_list,__div_equal,__id}, __assignment},
|
||||
{{__semi,__call_hash,__div_equal,__id}, __assignment},
|
||||
|
||||
{{__semi,__calculation,__link_equal,__id}, __assignment},
|
||||
{{__semi,__number,__link_equal,__id}, __assignment},
|
||||
{{__semi,__string,__link_equal,__id}, __assignment},
|
||||
{{__semi,__id,__link_equal,__id}, __assignment},
|
||||
{{__semi,__char,__link_equal,__id}, __assignment},
|
||||
{{__semi,__call_function,__link_equal,__id}, __assignment},
|
||||
{{__semi,__call_list,__link_equal,__id}, __assignment},
|
||||
{{__semi,__call_hash,__link_equal,__id}, __assignment},
|
||||
|
||||
{{__definition}, __statement},
|
||||
{{__assignment}, __statement},
|
||||
{{__statement,__statement}, __statement}
|
||||
};
|
||||
int num_of_par=sizeof(par)/sizeof(cmp_seq);
|
||||
|
||||
void print_token(int type)
|
||||
{
|
||||
std::string context="";
|
||||
switch(type)
|
||||
{
|
||||
case __stack_end:
|
||||
context="#";
|
||||
break;
|
||||
case __equal:
|
||||
context="=";
|
||||
break;
|
||||
case __cmp_equal:
|
||||
context="==";
|
||||
break;
|
||||
case __cmp_not_equal:
|
||||
context="!=";
|
||||
break;
|
||||
case __cmp_less:
|
||||
context="<";
|
||||
break;
|
||||
case __cmp_less_or_equal:
|
||||
context="<=";
|
||||
break;
|
||||
case __cmp_more:
|
||||
context=">";
|
||||
break;
|
||||
case __cmp_more_or_equal:
|
||||
context=">=";
|
||||
break;
|
||||
case __and_operator:
|
||||
context="and";
|
||||
break;
|
||||
case __or_operator:
|
||||
context="or";
|
||||
break;
|
||||
case __nor_operator:
|
||||
context="!";
|
||||
break;
|
||||
case __add_operator:
|
||||
context="+";
|
||||
break;
|
||||
case __sub_operator:
|
||||
context="-";
|
||||
break;
|
||||
case __mul_operator:
|
||||
context="*";
|
||||
break;
|
||||
case __div_operator:
|
||||
context="/";
|
||||
break;
|
||||
case __link_operator:
|
||||
context="~";
|
||||
break;
|
||||
case __add_equal:
|
||||
context="+=";
|
||||
break;
|
||||
case __sub_equal:
|
||||
context="-=";
|
||||
break;
|
||||
case __mul_equal:
|
||||
context="*=";
|
||||
break;
|
||||
case __div_equal:
|
||||
context="/=";
|
||||
break;
|
||||
case __link_equal:
|
||||
context="~=";
|
||||
break;
|
||||
case __left_brace:
|
||||
context="{";
|
||||
break;
|
||||
case __right_brace:
|
||||
context="}";
|
||||
break;
|
||||
case __left_bracket:
|
||||
context="[";
|
||||
break;
|
||||
case __right_bracket:
|
||||
context="]";
|
||||
break;
|
||||
case __left_curve:
|
||||
context="(";
|
||||
break;
|
||||
case __right_curve:
|
||||
context=")";
|
||||
break;
|
||||
case __semi:
|
||||
context=";";
|
||||
break;
|
||||
case __comma:
|
||||
context=",";
|
||||
break;
|
||||
case __colon:
|
||||
context=":";
|
||||
break;
|
||||
case __dot:
|
||||
context=".";
|
||||
break;
|
||||
case __var:
|
||||
context="var";
|
||||
break;
|
||||
case __func:
|
||||
context="func";
|
||||
break;
|
||||
case __id:
|
||||
context="id";
|
||||
break;
|
||||
case __dynamic_id:
|
||||
context="id...";
|
||||
break;
|
||||
case __number:
|
||||
context="number";
|
||||
break;
|
||||
case __string:
|
||||
context="string";
|
||||
break;
|
||||
case __char:
|
||||
context="char";
|
||||
break;
|
||||
case __continue:
|
||||
context="continue";
|
||||
break;
|
||||
case __break:
|
||||
context="break";
|
||||
break;
|
||||
case __for:
|
||||
context="for";
|
||||
break;
|
||||
case __forindex:
|
||||
context="forindex";
|
||||
break;
|
||||
case __foreach:
|
||||
context="foreach";
|
||||
break;
|
||||
case __while:
|
||||
context="while";
|
||||
break;
|
||||
case __if:
|
||||
context="if";
|
||||
break;
|
||||
case __elsif:
|
||||
context="elsif";
|
||||
break;
|
||||
case __else:
|
||||
context="else";
|
||||
break;
|
||||
case __return:
|
||||
context="return";
|
||||
break;
|
||||
case __call_list_head:
|
||||
context="id [";
|
||||
break;
|
||||
case __call_func_head:
|
||||
context="id (";
|
||||
break;
|
||||
case __func_head:
|
||||
context="func (";
|
||||
break;
|
||||
case __scalar:
|
||||
context="scalar";
|
||||
break;
|
||||
case __list:
|
||||
context="list";
|
||||
break;
|
||||
case __hash:
|
||||
context="hash";
|
||||
break;
|
||||
case __hash_member:
|
||||
context="hash_member";
|
||||
break;
|
||||
case __identifier:
|
||||
context="identifier";
|
||||
break;
|
||||
case __statement:
|
||||
context="statement";
|
||||
break;
|
||||
case __function:
|
||||
context="function";
|
||||
break;
|
||||
case __call_function:
|
||||
context="call_func";
|
||||
break;
|
||||
case __call_list:
|
||||
context="call_list";
|
||||
break;
|
||||
case __call_hash:
|
||||
context="call_hash";
|
||||
break;
|
||||
case __definition:
|
||||
context="definition";
|
||||
break;
|
||||
case __assignment:
|
||||
context="assignment";
|
||||
break;
|
||||
case __calculation:
|
||||
context="calc";
|
||||
break;
|
||||
case __loop:
|
||||
context="loop";
|
||||
break;
|
||||
case __choose:
|
||||
context="choose";
|
||||
break;
|
||||
case __program:
|
||||
context="program";
|
||||
break;
|
||||
|
||||
case __data_list:
|
||||
context="datas";
|
||||
break;
|
||||
default:
|
||||
context="unknown_type";
|
||||
break;
|
||||
}
|
||||
std::cout<<context;
|
||||
return;
|
||||
}
|
||||
|
||||
struct parse_unit
|
||||
{
|
||||
int line;
|
||||
int type;
|
||||
};
|
||||
class PDA
|
||||
{
|
||||
private:
|
||||
std::stack<int> main_stack;
|
||||
std::stack<int> comp_stack;
|
||||
public:
|
||||
void set_stack_empty()
|
||||
{
|
||||
while(!main_stack.empty())
|
||||
main_stack.pop();
|
||||
while(!comp_stack.empty())
|
||||
comp_stack.pop();
|
||||
main_stack.push(__stack_end);
|
||||
comp_stack.push(__stack_end);
|
||||
comp_stack.push(__program);
|
||||
}
|
||||
void stack_input(std::stack<parse_unit>& temp)
|
||||
{
|
||||
set_stack_empty();
|
||||
while(!temp.empty())
|
||||
{
|
||||
main_stack.push(temp.top().type);
|
||||
temp.pop();
|
||||
}
|
||||
return;
|
||||
}
|
||||
void print_stack(std::stack<int>& temp)
|
||||
{
|
||||
std::stack<int> t;
|
||||
while(!temp.empty())
|
||||
{
|
||||
t.push(temp.top());
|
||||
print_token(t.top());
|
||||
std::cout<<" ";
|
||||
temp.pop();
|
||||
}
|
||||
while(!t.empty())
|
||||
{
|
||||
temp.push(t.top());
|
||||
t.pop();
|
||||
}
|
||||
return;
|
||||
}
|
||||
void print_main_and_comp()
|
||||
{
|
||||
std::cout<<">>[Main stack] ";
|
||||
print_stack(main_stack);
|
||||
std::cout<<std::endl<<">>[Comp stack] ";
|
||||
print_stack(comp_stack);
|
||||
std::cout<<std::endl;
|
||||
return;
|
||||
}
|
||||
bool reducable()
|
||||
{
|
||||
std::stack<int> temp;
|
||||
for(int i=0;i<num_of_par;++i)
|
||||
{
|
||||
for(int j=max_len-1;j>=0;--j)
|
||||
{
|
||||
if(!par[i].tokens[j])
|
||||
continue;
|
||||
// if par[i].tokens[j] is 0 then continue until the tokens[j] is not 0
|
||||
temp.push(comp_stack.top());
|
||||
comp_stack.pop();
|
||||
if((par[i].tokens[j]!=temp.top()) || (comp_stack.empty() && par[i].tokens[j]))
|
||||
{
|
||||
while(!temp.empty())
|
||||
{
|
||||
comp_stack.push(temp.top());
|
||||
temp.pop();
|
||||
}
|
||||
break;
|
||||
}
|
||||
if((par[i].tokens[j]==temp.top()) && (j==0))
|
||||
{
|
||||
comp_stack.push(par[i].res);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void print_error()
|
||||
{
|
||||
while(!comp_stack.empty())
|
||||
{
|
||||
if((comp_stack.top()!=__statement) && (comp_stack.top()!=__program) && (comp_stack.top()!=__stack_end))
|
||||
{
|
||||
print_token(comp_stack.top());
|
||||
std::cout<<" ";
|
||||
}
|
||||
comp_stack.pop();
|
||||
}
|
||||
std::cout<<std::endl;
|
||||
return;
|
||||
}
|
||||
void main_comp_progress(bool show)
|
||||
{
|
||||
if(show)
|
||||
print_main_and_comp();
|
||||
while(main_stack.top()!=__stack_end)
|
||||
{
|
||||
comp_stack.push(main_stack.top());
|
||||
main_stack.pop();
|
||||
if(show)
|
||||
print_main_and_comp();
|
||||
while(1)
|
||||
{
|
||||
if(!reducable())
|
||||
break;
|
||||
if(show)
|
||||
print_main_and_comp();
|
||||
}
|
||||
}
|
||||
if(comp_stack.top()==__program)
|
||||
{
|
||||
comp_stack.pop();
|
||||
if(comp_stack.top()==__stack_end)
|
||||
std::cout<<">>[Parse] 0 error(s)."<<std::endl;
|
||||
else
|
||||
{
|
||||
std::cout<<">>[Parse] Error:"<<std::endl;
|
||||
print_error();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout<<">>[Parse] Error:"<<std::endl;
|
||||
print_error();
|
||||
}
|
||||
std::cout<<">>[Parse] Complete checking."<<std::endl;
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
class nasal_parser
|
||||
{
|
||||
private:
|
||||
std::stack<parse_unit> parser;
|
||||
public:
|
||||
void parse_process(std::list<token>& lexer,bool show)
|
||||
{
|
||||
while(!parser.empty())
|
||||
parser.pop();
|
||||
for(std::list<token>::iterator i=lexer.begin();i!=lexer.end();++i)
|
||||
{
|
||||
parse_unit temp_parse;
|
||||
temp_parse.line=(*i).line;
|
||||
if(((*i).content=="var") || ((*i).content=="func") || ((*i).content=="return") || ((*i).content=="nil") || ((*i).content=="continue") || ((*i).content=="break") || ((*i).content=="and") || ((*i).content=="or"))
|
||||
{
|
||||
if((*i).content=="var")
|
||||
temp_parse.type=__var;
|
||||
else if((*i).content=="func")
|
||||
temp_parse.type=__func;
|
||||
else if((*i).content=="return")
|
||||
temp_parse.type=__return;
|
||||
else if((*i).content=="nil")
|
||||
temp_parse.type=__number;
|
||||
else if((*i).content=="continue")
|
||||
temp_parse.type=__continue;
|
||||
else if((*i).content=="break")
|
||||
temp_parse.type=__break;
|
||||
else if((*i).content=="and")
|
||||
temp_parse.type=__and_operator;
|
||||
else if((*i).content=="or")
|
||||
temp_parse.type=__or_operator;
|
||||
}
|
||||
else if((*i).type==IDENTIFIER)
|
||||
{
|
||||
temp_parse.type=__id;
|
||||
}
|
||||
else if((*i).type==CALL_LIST)
|
||||
{
|
||||
temp_parse.type=__call_list_head;
|
||||
}
|
||||
else if((*i).type==CALL_FUNC)
|
||||
{
|
||||
temp_parse.type=__call_func_head;
|
||||
}
|
||||
else if((*i).type==FUNC_HEAD)
|
||||
{
|
||||
temp_parse.type=__func_head;
|
||||
}
|
||||
else if((*i).type==DYNAMIC_ID)
|
||||
{
|
||||
temp_parse.type=__dynamic_id;
|
||||
}
|
||||
else if(((*i).content=="for") || ((*i).content=="foreach") || ((*i).content=="while") || ((*i).content=="forindex"))
|
||||
{
|
||||
if((*i).content=="for")
|
||||
temp_parse.type=__for;
|
||||
else if((*i).content=="forindex")
|
||||
temp_parse.type=__forindex;
|
||||
else if((*i).content=="foreach")
|
||||
temp_parse.type=__foreach;
|
||||
else if((*i).content=="while")
|
||||
temp_parse.type=__while;
|
||||
}
|
||||
else if(((*i).content=="if") || ((*i).content=="else") || ((*i).content=="elsif"))
|
||||
{
|
||||
if((*i).content=="if")
|
||||
temp_parse.type=__if;
|
||||
else if((*i).content=="else")
|
||||
temp_parse.type=__else;
|
||||
else if((*i).content=="elsif")
|
||||
temp_parse.type=__elsif;
|
||||
}
|
||||
else if(((*i).content=="==") || ((*i).content=="!=") || ((*i).content==">") || ((*i).content==">=") || ((*i).content=="<") || ((*i).content=="<="))
|
||||
{
|
||||
if((*i).content=="==")
|
||||
temp_parse.type=__cmp_equal;
|
||||
else if((*i).content=="!=")
|
||||
temp_parse.type=__cmp_not_equal;
|
||||
else if((*i).content==">")
|
||||
temp_parse.type=__cmp_more;
|
||||
else if((*i).content==">=")
|
||||
temp_parse.type=__cmp_more_or_equal;
|
||||
else if((*i).content=="<")
|
||||
temp_parse.type=__cmp_less;
|
||||
else if((*i).content=="<=")
|
||||
temp_parse.type=__cmp_less_or_equal;
|
||||
}
|
||||
else if(((*i).content==";") || ((*i).content==",") || ((*i).content=="=") || ((*i).content==":") || ((*i).content=="."))
|
||||
{
|
||||
if((*i).content==";")
|
||||
temp_parse.type=__semi;
|
||||
else if((*i).content==",")
|
||||
temp_parse.type=__comma;
|
||||
else if((*i).content=="=")
|
||||
temp_parse.type=__equal;
|
||||
else if((*i).content==":")
|
||||
temp_parse.type=__colon;
|
||||
else if((*i).content==".")
|
||||
temp_parse.type=__dot;
|
||||
}
|
||||
else if(((*i).type==NUMBER) || ((*i).type==STRING) || ((*i).type==CHAR))
|
||||
{
|
||||
if((*i).type==NUMBER)
|
||||
temp_parse.type=__number;
|
||||
else if((*i).type==STRING)
|
||||
temp_parse.type=__string;
|
||||
else if((*i).type==CHAR)
|
||||
temp_parse.type=__char;
|
||||
}
|
||||
else if(((*i).content=="+") || ((*i).content=="-") || ((*i).content=="*") || ((*i).content=="/") || ((*i).content=="~") || ((*i).content=="!"))
|
||||
{
|
||||
if((*i).content=="+")
|
||||
temp_parse.type=__add_operator;
|
||||
else if((*i).content=="-")
|
||||
temp_parse.type=__sub_operator;
|
||||
else if((*i).content=="*")
|
||||
temp_parse.type=__mul_operator;
|
||||
else if((*i).content=="/")
|
||||
temp_parse.type=__div_operator;
|
||||
else if((*i).content=="~")
|
||||
temp_parse.type=__link_operator;
|
||||
else if((*i).content=="!")
|
||||
temp_parse.type=__nor_operator;
|
||||
}
|
||||
else if(((*i).content=="+=") || ((*i).content=="-=") || ((*i).content=="*=") || ((*i).content=="/=") || ((*i).content=="~="))
|
||||
{
|
||||
if((*i).content=="+=")
|
||||
temp_parse.type=__add_equal;
|
||||
else if((*i).content=="-=")
|
||||
temp_parse.type=__sub_equal;
|
||||
else if((*i).content=="*=")
|
||||
temp_parse.type=__mul_equal;
|
||||
else if((*i).content=="/=")
|
||||
temp_parse.type=__div_equal;
|
||||
else if((*i).content=="~=")
|
||||
temp_parse.type=__link_equal;
|
||||
}
|
||||
else if(((*i).content=="(") || ((*i).content==")") || ((*i).content=="[") || ((*i).content=="]") || ((*i).content=="{") || ((*i).content=="}"))
|
||||
{
|
||||
char c=(*i).content[0];
|
||||
switch(c)
|
||||
{
|
||||
case '(':
|
||||
temp_parse.type=__left_curve;
|
||||
break;
|
||||
case ')':
|
||||
temp_parse.type=__right_curve;
|
||||
break;
|
||||
case '[':
|
||||
temp_parse.type=__left_bracket;
|
||||
break;
|
||||
case ']':
|
||||
temp_parse.type=__right_bracket;
|
||||
break;
|
||||
case '{':
|
||||
temp_parse.type=__left_brace;
|
||||
break;
|
||||
case '}':
|
||||
temp_parse.type=__right_brace;
|
||||
break;
|
||||
}
|
||||
}
|
||||
parser.push(temp_parse);//push this into stack
|
||||
}
|
||||
if(parser.empty())
|
||||
{
|
||||
std::cout<<">>[Warning] Empty lexer."<<std::endl;
|
||||
std::cout<<">>[Parse] Complete checking."<<std::endl;
|
||||
return;
|
||||
}
|
||||
std::stack<parse_unit> temp;
|
||||
while(!parser.empty())
|
||||
{
|
||||
temp.push(parser.top());
|
||||
parser.pop();
|
||||
}
|
||||
PDA automata;
|
||||
automata.stack_input(temp);
|
||||
automata.main_comp_progress(show);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue