硬写就行了
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <fstream>
#include <sstream>
#include <set>
#include <map>
#include <regex>
#include <cstdarg>
#include <cassert>
#include <algorithm>
using namespace std;
[[noreturn]] void err(const char *fmt, ...){
va_list argptr;
va_start(argptr,fmt);
vprintf(fmt,argptr);
va_end(argptr);
exit(0);
}
const string Keywords[]={"if","else","while","for","switch","case","return","new","delete","inline","do",
"true","false","class","struct","contiune","break","try","catch","const","enum","using","namespace","auto",
"static","public","private","protected","friend","operator","sizeof","template","typename","goto","typedef","register","long","int"};
const string Operators[]={"+","-","*","/","%","=",";","<",">","<<",">>","&","|","&&","||","(",")","[","]","{","}",">=","<=","==","!=",".","+=","-=","*=","/=",",","!"};
map<string, int> Keywords_;
map<string, int> Operators_;
vector<string> id_str;
map<string, int> str_id;
void append_id(const string &s){
str_id[s]=(int)id_str.size();
id_str.push_back(s);
}
int inputs[2000010], inputs_p, inputs_size;
void init(){
cin>>inputs_size;
for (int i=0;i<inputs_size;i++) cin>>inputs[i];
int c=0;
for (auto &s:Keywords) Keywords_[s]=c++;
c=0;
for (auto &s:Operators) Operators_[s]=c++;
append_id("cin");
append_id("cout");
append_id("endl");
}
enum TokenType{INT,FLOAT,STRING,CHAR,KEYWORD,ID,OPERATOR};
struct Token{
TokenType type;
int val;
bool operator==(Token &tok){return type==tok.type && val==tok.val;}
Token(TokenType type, int val):type(type), val(val){}
void debug(){
switch (type){
case INT: cout<<val; break;
case KEYWORD: cout<<Keywords[val]; break;
case OPERATOR: cout<<Operators[val]; break;
case ID: cout<<id_str[val]; break;
default: ;
}
}
bool equal(int tp, const string &str){
if (tp!=type) return 0;
if (type==OPERATOR) return Operators[val]==str;
if (type==KEYWORD) return Keywords[val]==str;
if (type==ID) return id_str[val]==str;
err("Error %s\n",__LINE__);
};
};
vector<Token> tok;
void tokenlize(char *s){
char *cur=s;
char tmp[128];
if (s[0]=='#') return;
while (*cur){
if (isdigit(*cur)){
int t=0;
while (isdigit(*cur)) t=t*10+*cur-'0',cur++;
tok.emplace_back(INT, t);
}
else if (isalpha(*cur) || *cur=='_'){
char *t=tmp;
while (isalpha(*cur) || *cur=='_' || isdigit(*cur)) *t=*cur, t++, cur++;
*t=0;
string s1(tmp);
if (Keywords_.count(s1)){
tok.emplace_back(KEYWORD, Keywords_[s1]);
}
else{
if (!str_id.count(s1))
append_id(s1);
tok.emplace_back(ID, str_id[s1]);
}
}
else if (*cur=='\''){
cur++;
while (*cur!='\'') cur++;
cur++;
}
else if (*cur=='\"'){
cur++;
while (*cur!='\"') cur++;
cur++;
}
else if (isspace(*cur)){
cur++;
}
else{
tmp[0]=*cur; cur++;
tmp[1]=*cur; cur++;
tmp[2]=0;
string s1(tmp);
if (tmp[1] && Operators_.count(s1))
tok.emplace_back(OPERATOR, Operators_[s1]);
else{
tmp[1]=0;
cur--;
s1=string(tmp);
if (Operators_.count(s1))
tok.emplace_back(OPERATOR, Operators_[s1]);
else
err("Unkonwn operator %s\n",s1.c_str());
}
}
}
}
char line[1000];
int tokp;
void eat(TokenType type, const string &s){
if (!tok[tokp].equal(type, s)){
puts("[Error] Read ");
tok[tokp].debug();
err("expect %s\n", s.c_str());
}
tokp++;
}
struct ASTNode{
enum Type{
FUNC,
STMTS,
STMT,
UNIT10,UNIT9,UNIT8,UNIT7,UNIT6,UNIT5,UNIT4,UNIT3,UNIT2,UNIT1,UNIT0,
INT,
ID,
VAR,
DEFINES
};
const static string name[18];
void debug(){
cout<<name[type]<<' ';
switch(type){
case VAR:
case DEFINES:
case STMT:
case STMTS:
case UNIT0:
case FUNC: break;
case INT: cout<<val; break;
case ID: cout<<id_str[val]; break;
default: cout<<Operators[val]; break;
}
cout<<'\n';
}
void debugdfs(int deep=0){
for (int i=0;i<deep;i++) cout<<" ";
debug();
for (auto p:ch) p->debugdfs(deep+1);
}
Type type;
int val;
ASTNode(Type type):type(type){}
ASTNode(Type type, int val):type(type),val(val){}
vector<ASTNode *> ch;
};
const string ASTNode::name[18]={"FUNC","STMTS","STMT","UNIT10","UNIT9","UNIT8","UNIT7","UNIT6","UNIT5","UNIT4","UNIT3","UNIT2","UNIT1","UNIT0","INT","ID","VAR","DEFINES"};
map<int, ASTNode*> funcs;
vector<ASTNode*> global_vars;
ASTNode* parse_expr();
ASTNode* parse_id(){
return new ASTNode(ASTNode::ID, tok[tokp++].val);
}
ASTNode* parse_int(){
return new ASTNode(ASTNode::INT, tok[tokp++].val);
}
ASTNode* parse_var(){
auto node=new ASTNode(ASTNode::VAR);
node->ch.push_back(parse_id());
while (tok[tokp].equal(OPERATOR, "[")){
tokp++; //[
node->ch.push_back(parse_expr());
eat(OPERATOR, "]"); //]
}
return node;
}
ASTNode* parse_unit0(){
ASTNode *node;
if (tok[tokp].equal(OPERATOR,"(")){
tokp++; //(
node=parse_expr();
eat(OPERATOR, ")"); //)
}
else if (tok[tokp+1].equal(OPERATOR,"(")){ //func
node=new ASTNode(ASTNode::UNIT0, 0);
node->ch.push_back(parse_id());
while (tok[tokp].equal(OPERATOR, "(") || tok[tokp].equal(OPERATOR, ",") ){
tokp++; //( or ,
if (tok[tokp].equal(OPERATOR,")")) break;
node->ch.push_back(parse_expr());
}
eat(OPERATOR, ")"); //)
return node;
}
else if (tok[tokp].type==INT){
node=new ASTNode(ASTNode::UNIT0, 2);
node->ch.push_back(parse_int());
}
else{ //var
node=new ASTNode(ASTNode::UNIT0, 1);
node->ch.push_back(parse_var());
}
return node;
}
ASTNode* parse_unit1(){
if (tok[tokp].equal(OPERATOR,"+") || tok[tokp].equal(OPERATOR,"-")
|| tok[tokp].equal(OPERATOR,"!")){
auto node=new ASTNode(ASTNode::UNIT1, tok[tokp].val);
tokp++;
auto left=parse_unit1();
node->ch.push_back(left);
return node;
}
else return parse_unit0();
}
ASTNode* parse_unit2(){
auto left=parse_unit1();
while (tok[tokp].equal(OPERATOR,"*") || tok[tokp].equal(OPERATOR,"/") || tok[tokp].equal(OPERATOR,"%")){
auto node=new ASTNode(ASTNode::UNIT2, tok[tokp].val);
node->val=tok[tokp].val; tokp++;
node->ch.push_back(left);
node->ch.push_back(parse_unit1());
left=node;
}
return left;
}
ASTNode* parse_unit3(){
auto left=parse_unit2();
while (tok[tokp].equal(OPERATOR,"+") || tok[tokp].equal(OPERATOR,"-")){
auto node=new ASTNode(ASTNode::UNIT3, tok[tokp].val);
node->val=tok[tokp].val; tokp++;
node->ch.push_back(left);
node->ch.push_back(parse_unit2());
left=node;
}
return left;
}
ASTNode* parse_unit4(){
auto left=parse_unit3();
while (tok[tokp].equal(OPERATOR,">") || tok[tokp].equal(OPERATOR,">=") ||
tok[tokp].equal(OPERATOR,"<") || tok[tokp].equal(OPERATOR,"<=") ){
auto node=new ASTNode(ASTNode::UNIT4, tok[tokp].val);
node->val=tok[tokp].val; tokp++;
node->ch.push_back(left);
node->ch.push_back(parse_unit3());
left=node;
}
return left;
}
ASTNode* parse_unit5(){
auto left=parse_unit4();
while (tok[tokp].equal(OPERATOR,"==") || tok[tokp].equal(OPERATOR,"!=")){
auto node=new ASTNode(ASTNode::UNIT5, tok[tokp].val);
node->val=tok[tokp].val; tokp++;
node->ch.push_back(left);
node->ch.push_back(parse_unit4());
left=node;
}
return left;
}
ASTNode* parse_unit6(){
auto left=parse_unit5();
while (tok[tokp].equal(OPERATOR,"^")){
auto node=new ASTNode(ASTNode::UNIT6, tok[tokp].val);
node->val=tok[tokp].val; tokp++;
node->ch.push_back(left);
node->ch.push_back(parse_unit5());
left=node;
}
return left;
}
ASTNode* parse_unit7(){
auto left=parse_unit6();
while (tok[tokp].equal(OPERATOR,"&&")){
auto node=new ASTNode(ASTNode::UNIT7, tok[tokp].val);
node->val=tok[tokp].val; tokp++;
node->ch.push_back(left);
node->ch.push_back(parse_unit6());
left=node;
}
return left;
}
ASTNode* parse_unit8(){
auto left=parse_unit7();
while (tok[tokp].equal(OPERATOR,"||")){
auto node=new ASTNode(ASTNode::UNIT8, tok[tokp].val);
node->val=tok[tokp].val; tokp++;
node->ch.push_back(left);
node->ch.push_back(parse_unit7());
left=node;
}
return left;
}
ASTNode* parse_unit9(){
auto left=parse_unit8();
if (tok[tokp].equal(OPERATOR,"=")){
auto node=new ASTNode(ASTNode::UNIT9, tok[tokp].val);
node->val=tok[tokp].val; tokp++;
node->ch.push_back(left);
node->ch.push_back(parse_unit9());
return node;
}
else return left;
}
ASTNode* parse_unit10(){
auto left=parse_unit9();
while (tok[tokp].equal(OPERATOR,">>") || tok[tokp].equal(OPERATOR,"<<")){
auto node=new ASTNode(ASTNode::UNIT10, tok[tokp].val);
node->val=tok[tokp].val; tokp++;
node->ch.push_back(left);
node->ch.push_back(parse_unit9());
left=node;
}
return left;
}
ASTNode* parse_expr(){
return parse_unit10();
}
ASTNode* parse_defines(){
tokp++; // <type-id>
auto node=new ASTNode(ASTNode::DEFINES);
node->ch.push_back(parse_var());
while (!tok[tokp].equal(OPERATOR, ";")){
eat(OPERATOR, ",");
node->ch.push_back(parse_var());
}
return node;
}
ASTNode* parse_for_stmt(){
auto node=new ASTNode(ASTNode::STMT);
auto &ch=node->ch;
if (tok[tokp].equal(OPERATOR,";") || tok[tokp].equal(OPERATOR,")")){ //empty
node->val=7;
}
else if (tok[tokp].equal(KEYWORD,"int")){
node->val=5;
tokp++;
ch.push_back(parse_defines());
}
else{
node->val=6;
ch.push_back(parse_expr());
}
return node;
}
ASTNode* parse_stmts();
ASTNode* parse_stmt(){
auto node=new ASTNode(ASTNode::STMT);
auto &ch=node->ch;
if (tok[tokp].equal(KEYWORD,"if")){
tokp++;
node->val=0;
eat(OPERATOR, "(");
ch.push_back(parse_expr());
eat(OPERATOR, ")");
ch.push_back(parse_stmt());
if (tok[tokp].equal(KEYWORD, "else")){
tokp++;
ch.push_back(parse_stmt());
}
}
else if (tok[tokp].equal(KEYWORD,"while")){
tokp++;
node->val=1;
eat(OPERATOR, "(");
ch.push_back(parse_expr());
eat(OPERATOR, ")");
ch.push_back(parse_stmt());
}
else if (tok[tokp].equal(KEYWORD,"for")){
tokp++;
node->val=2;
eat(OPERATOR, "(");
ch.push_back(parse_for_stmt());
eat(OPERATOR, ";");
ch.push_back(parse_for_stmt());
eat(OPERATOR, ";");
ch.push_back(parse_for_stmt());
eat(OPERATOR, ")");
ch.push_back(parse_stmt());
}
else if (tok[tokp].equal(KEYWORD,"return")){
node->val=3;
tokp++;
ch.push_back(parse_expr());
eat(OPERATOR, ";");
}
else if (tok[tokp].equal(OPERATOR,"{")){
tokp++; //{
node->val=4;
ch.push_back(parse_stmts());
eat(OPERATOR, "}");
}
else if (tok[tokp].equal(OPERATOR,";")){ //empty
tokp++;
node->val=7;
}
else if (tok[tokp].equal(KEYWORD,"using")){ //empty
while (!tok[tokp].equal(OPERATOR, ";")) tokp++;
tokp++;
node->val=7;
}
else if (tok[tokp].equal(KEYWORD,"int")){
node->val=5;
ch.push_back(parse_defines());
eat(OPERATOR, ";");
}
else{
node->val=6;
ch.push_back(parse_expr());
eat(OPERATOR, ";");
}
return node;
}
ASTNode* parse_stmts(){
auto node=new ASTNode(ASTNode::STMTS);
while (!tok[tokp].equal(OPERATOR,"}")){
node->ch.push_back(parse_stmt());
}
return node;
}
ASTNode* parse_func(){
tokp++; //<type>
auto node=new ASTNode(ASTNode::FUNC, tok[tokp].val);
node->ch.push_back(parse_id());
tokp++; //(
while(!tok[tokp].equal(OPERATOR, ")")){
tokp++; //<type>
node->ch.push_back(parse_id());
if (!tok[tokp].equal(OPERATOR, ")"))
eat(OPERATOR,",");
}
tokp++; //)
eat(OPERATOR, "{");
node->ch.push_back(parse_stmts());
eat(OPERATOR, "}");
return node;
}
void parse_root(){
while (tokp<(int)tok.size()){
if (tok[tokp+2].equal(OPERATOR, "(")){ //func
int fun_id=tok[tokp+1].val;
auto ret=parse_func();
//ret->debugdfs();
funcs[fun_id]=ret;
}
else{ //define vars
global_vars.push_back(parse_stmt());
}
}
}
int mem[4200000];
struct VarInfo{
int pos;
bool isarray;
vector<int> dim;
int repos(const vector<int> &v){
assert(v.size()==dim.size());
int b=1,sum=0;
for (int i=(int)dim.size()-1;i>=0;i--){
sum+=v[i]*b;
b*=dim[i];
}
return pos+sum;
}
};
int cur_pos=1;
int func_dep;
stack<int> base_pos;
vector<map<int,VarInfo>> id_info;
vector<int> pre_scope;
bool return_flag;
#define ENDL 3
void in_scope(int _pre_scope){
base_pos.push(cur_pos);
pre_scope.push_back(_pre_scope);
id_info.emplace_back();
}
void out_scope(){
cur_pos=base_pos.top();
base_pos.pop();
pre_scope.pop_back();
id_info.pop_back();
}
void alloc(int id, const vector<int> &dim, int init_val=0){
if (dim.size()==0){
id_info.back()[id]=VarInfo({cur_pos, 0, vector<int> ()});
mem[cur_pos]=init_val;
cur_pos++;
}
else{
id_info.back()[id]=VarInfo({cur_pos, 0, vector<int> (dim)});
int len=accumulate(begin(dim),end(dim),1,[](int x, int y){return x*y;});
fill(mem+cur_pos,mem+cur_pos+len,0);
cur_pos+=len;
}
}
int read_var(int id, const vector<int> &dim){
for (int i=(int)id_info.size()-1;i>=0;i=pre_scope[i])
if(id_info[i].count(id)){
if (dim.size()==0) return id_info[i][id].pos;
return id_info[i][id].repos(dim);
}
err("var %s not defined\n", id_str[id].c_str());
}
void run_stmts(ASTNode *node);
int run_expr(ASTNode *node);
int run_var(ASTNode *node){
int id=(node->ch[0])->val;
vector<int> dim;
for (int i=1;i<(int)node->ch.size();i++){
int ret=run_expr(node->ch[i]);
dim.push_back(mem[ret]);
}
return read_var(id, dim);
}
void run_stmts(ASTNode *node);
void run_func(ASTNode *node, const vector<int> &args){
in_scope(0);
func_dep++;
return_flag=0;
auto &ch=node->ch;
if (ch.size()!=args.size()+2)
err("arg list mismatch\n");
for (int i=1;i<(int)ch.size()-1;i++){
alloc(ch[i]->val, vector<int> (), args[i-1]);
}
run_stmts(ch.back());
if (return_flag==0) *mem=0;
return_flag=0;
func_dep--;
out_scope();
}
void run_funccall(ASTNode *node){
int id=node->ch[0]->val;
vector<int> args;
for (int i=1;i<(int)node->ch.size();i++){
int ret=run_expr(node->ch[i]);
args.push_back(mem[ret]);
}
if (id_str[id]==string("putchar")){
*mem=putchar(args[0]);
return;
}
//for (int i=0;i<func_dep;i++) cout<<" "; cout<<"Calling func "<<id_str[id]<<", args: "; for (auto x:args) cout<<x<<' '; cout<<'\n';
if (!funcs.count(id)) err("[Error] no such function to call %s", id_str[id].c_str());
run_func(funcs[id], args);
}
int run_expr(ASTNode *node){
if (node->type==ASTNode::UNIT0){
if (node->val==1)
return run_var(node->ch[0]);
else if (node->val==2)
*mem=node->ch[0]->val;
else
run_funccall(node);
return 0;
}
int op=node->val;
int vall,valr=-1;
vall=run_expr(node->ch[0]);
int tmp=mem[vall];
if (node->ch.size()>1)
valr=run_expr(node->ch[1]);
if (Operators[op]=="="){
if (vall==0) err("rvalue can't be assigned\n");
mem[vall]=mem[valr];
return vall;
}
else if (Operators[op]=="+"){
if (valr==-1) *mem=tmp;
else *mem=tmp+mem[valr];
return 0;
}
else if (Operators[op]=="-"){
if (valr==-1) *mem=-tmp;
else *mem=tmp-mem[valr];
return 0;
}
else if (Operators[op]=="!"){
*mem=!tmp;
return 0;
}
else if (Operators[op]=="*"){
*mem=tmp*mem[valr];
return 0;
}
else if (Operators[op]=="/"){
*mem=tmp/mem[valr];
return 0;
}
else if (Operators[op]=="=="){
*mem=tmp==mem[valr];
return 0;
}
else if (Operators[op]=="!="){
*mem=tmp!=mem[valr];
return 0;
}
else if (Operators[op]==">="){
*mem=tmp>=mem[valr];
return 0;
}
else if (Operators[op]=="<="){
*mem=tmp<=mem[valr];
return 0;
}
else if (Operators[op]==">"){
*mem=tmp>mem[valr];
return 0;
}
else if (Operators[op]=="<"){
*mem=tmp<mem[valr];
return 0;
}
else if (Operators[op]=="%"){
*mem=tmp%mem[valr];
return 0;
}
else if (Operators[op]=="^"){
*mem=(!!tmp)^(!!mem[valr]);
return 0;
}
else if (Operators[op]=="&&"){ //no short
*mem=tmp&&mem[valr];
return 0;
}
else if (Operators[op]=="||"){
*mem=tmp||mem[valr];
return 0;
}
else if (Operators[op]=="<<"){
int ret;
if (valr==ENDL) ret=bool(cout<<endl);
else ret=bool(cout<<mem[valr]);
*mem=ret;
return 0;
}
else if (Operators[op]==">>"){
if (valr==0) err("cin: rvalue can't be assigned");
if (inputs_p==inputs_size) *mem=0;
else mem[valr]=inputs[inputs_p++],*mem=1;
return 0;
}
throw;
}
void run_defines(ASTNode *node){
for (auto ch:node->ch){
vector<int> dim;
for (int i=1;i<(int)ch->ch.size();i++){
int ret=run_expr(ch->ch[i]);
dim.push_back(mem[ret]);
}
alloc(ch->ch[0]->val, dim);
}
}
void run_stmt(ASTNode *node){
if (return_flag) return;
if (node->val==0){ //if
if (mem[run_expr(node->ch[0])])
run_stmt(node->ch[1]);
else if (node->ch.size()>2){
run_stmt(node->ch[2]);
}
}
else if (node->val==1){ //while
while (1){
if (mem[run_expr(node->ch[0])] == 0) break;
run_stmt(node->ch[1]);
if (return_flag) return;
}
}
else if (node->val==2){ //for
run_stmt(node->ch[0]);
while (1){
*mem=1;
run_stmt(node->ch[1]);
if (*mem == 0) break;
run_stmt(node->ch[3]);
if (return_flag) return;
run_stmt(node->ch[2]);
}
}
else if (node->val==3){ //return
int ret=run_expr(node->ch[0]);
*mem=mem[ret];
return_flag=1;
}
else if (node->val==4){ //stmts
in_scope(pre_scope.size()-1);
run_stmts(node->ch[0]);
out_scope();
}
else if (node->val==5){ //define
run_defines(node->ch[0]);
}
else if (node->val==6){ //expr
*mem=mem[run_expr(node->ch[0])];
}
}
void run_stmts(ASTNode *node){
for (auto p:node->ch)
run_stmt(p);
}
void run_root(){
in_scope(-1);
alloc(str_id["cin"], vector<int>());
alloc(str_id["cout"], vector<int>());
alloc(str_id["endl"], vector<int>());
for (auto p:global_vars)
run_stmt(p);
run_func(funcs[str_id["main"]], vector<int> ());
}
int main(){
freopen("1.cpp","r",stdin);
init();
while (fgets(line,1000,stdin)){
//printf("%s",line);
tokenlize(line);
}
/*
int f=0;
for (int i=0;i<tok.size();i++){
if (tok[i].equal(ID, "function61") || tok[i].equal(ID,"function6") || tok[i].equal(ID,"Test6")) f=1;
if (f)
tok[i].debug();
}*/
parse_root();
run_root();
return 0;
}
de了一堆bug才过
#bug | 现象 | 原因及解决 |
8 | 表达式计算错误 | ‘%’符号未被正确计算 |
9 | – | 未判断for结束条件空的情况 |
10 | for循环内return导致程序无法终止 | 运行完一次内部stmt后未检查return_flag |
11 | 被调用函数中未定义的变量会引用外层函数变量 | 修改作用域规则 |
12 | 运行错误 | 变量内存太小 |
13 | for循环无法结束 | 运行for结束条件stmt时,未将单个expr左值转为右值 |
14 | – | 未将if等语句的expr左值转为右值 |
15 | – | 增加putchar函数的返回值 |
16 | WA10-Test6 | 未考虑嵌套作用域 |