138 lines
5.7 KiB
C++
138 lines
5.7 KiB
C++
#pragma once
|
|
|
|
#include "Lexer.hpp"
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <cstdlib>
|
|
#include <format>
|
|
#include <iostream>
|
|
#include <map>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
#include <utility>
|
|
#include <variant>
|
|
#include <vector>
|
|
|
|
namespace ztl{
|
|
inline void interpreter(const std::vector<Token> &tokens){
|
|
using ObjectType = std::variant<int64_t>;
|
|
std::map<std::string, ObjectType> objects;
|
|
const auto getValueOrLiteral = [&tokens,&objects](size_t i){
|
|
ObjectType a;
|
|
if(tokens[i].type==TokenType::Literal){
|
|
a=atoi(tokens[i].str.data());
|
|
}else if(tokens[i].type==TokenType::Identifier){
|
|
if(auto it = objects.find(tokens[i].str);it!=objects.end()){
|
|
a=(*it).second;
|
|
}else{
|
|
throw std::runtime_error(std::format("error in getting value named '{}'",tokens[i].str));
|
|
}
|
|
}else{
|
|
throw std::runtime_error("error in getting expression result");
|
|
}
|
|
return a;
|
|
};
|
|
const auto getExprAns = [&getValueOrLiteral,&objects,&tokens](size_t i)->std::pair<ObjectType, size_t>{
|
|
ObjectType a=getValueOrLiteral(i);
|
|
ObjectType b;
|
|
if(i+1<tokens.size()&&tokens[i+1].type==TokenType::Operator){
|
|
if(tokens[i+1].type==TokenType::Operator){
|
|
if(i+2<tokens.size()){
|
|
b=getValueOrLiteral(i+2);
|
|
}else{
|
|
throw std::runtime_error(std::format("error getting a op b, b is not found. a named '{}'",tokens[i].str));
|
|
}
|
|
}else{
|
|
throw std::runtime_error(std::format("unknown operator '{}'",tokens[i+1].str));
|
|
}
|
|
}else{
|
|
return {a,1};
|
|
}
|
|
ObjectType res;
|
|
if(std::holds_alternative<int64_t>(a) && std::holds_alternative<int64_t>(b)){
|
|
if(tokens[i+1].str=="+"){
|
|
res = std::get<int64_t>(a) + std::get<int64_t>(b);
|
|
}else if(tokens[i+1].str=="-"){
|
|
res = std::get<int64_t>(a) - std::get<int64_t>(b);
|
|
}
|
|
else{
|
|
throw std::runtime_error(std::format("unknown operator '{}' ",tokens[i+1].str));
|
|
}
|
|
}else{
|
|
throw std::runtime_error(std::format("unknown value type '{}' ,'{}'",tokens[i].str,tokens[i+2].str));
|
|
}
|
|
|
|
return {res,3};
|
|
};
|
|
for(size_t i=0;i<tokens.size();i++){
|
|
const auto eat = [&i,&tokens](const std::string &s){
|
|
if(i+1<tokens.size()&&tokens[i+1].str==s){
|
|
i++;
|
|
}else{
|
|
throw std::runtime_error(std::format("cannot get '{}' after '{}'",s,tokens[i].str));
|
|
}
|
|
};
|
|
if(tokens[i].type==TokenType::Keyword){
|
|
if(tokens[i].str=="int"){
|
|
if( i+2<tokens.size()
|
|
&&tokens[i+1].type==TokenType::Identifier
|
|
&& tokens[i+2].str=="="
|
|
){
|
|
std::string valueName = tokens[i+1].str;
|
|
i+=2;
|
|
auto res = getExprAns(i+1);
|
|
objects[valueName] = res.first;
|
|
i+=res.second;
|
|
}else{
|
|
throw std::runtime_error(std::format("error when creatting int value '{}'",tokens[i].str));
|
|
}
|
|
}
|
|
else if(tokens[i].str=="print"){
|
|
if(i+1<tokens.size()&&tokens[i+1].str=="("){
|
|
i++;
|
|
}else{
|
|
throw std::runtime_error("cannot get '(' when printing value");
|
|
}
|
|
if(!(i+1<tokens.size()))throw std::runtime_error("cannot get value be printed when printing value");
|
|
auto [res,addi] = getExprAns(i+1);
|
|
i+=addi;
|
|
if(i+1<tokens.size()&&tokens[i+1].str==")"){
|
|
i++;
|
|
}else{
|
|
throw std::runtime_error("cannot get ')' when printing value");
|
|
}
|
|
std::visit([](auto &res){
|
|
std::cout<<res<<'\n';
|
|
},res);
|
|
}
|
|
else{
|
|
throw std::runtime_error(std::format("interpreter error Cannot find Keyword '{}'",tokens[i].str));
|
|
}
|
|
|
|
}else if(tokens[i].type==TokenType::Identifier){
|
|
if( i+1<tokens.size()
|
|
&& tokens[i+1].str=="="
|
|
){
|
|
std::string valueName = tokens[i].str;
|
|
i+=1;
|
|
auto res = getExprAns(i+1);
|
|
if(auto it = objects.find(valueName);it!=objects.end()){
|
|
if(it->second.index()!=res.first.index()){
|
|
throw std::runtime_error(std::format("cannot give value to {}, because type is not same",valueName));
|
|
}
|
|
}else{
|
|
throw std::runtime_error(std::format("error when getting int value named '{}'",valueName));
|
|
}
|
|
objects[valueName] = res.first;
|
|
i+=res.second;
|
|
}else{
|
|
throw std::runtime_error(std::format("error when creatting int value '{}'",tokens[i].str));
|
|
}
|
|
}
|
|
else{
|
|
throw std::runtime_error(std::format("interpreter error at '{}'",tokens[i].str));
|
|
}
|
|
eat(";");
|
|
}
|
|
}
|
|
} |