Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #ifndef MYLISP_HPP
- #define MYLISP_HPP
- struct VM;
- struct Atom;
- struct Buffer;
- struct Cons;
- struct Buffer {
- uint32_t size;
- uint8_t* data;
- } bval;
- struct Cons {
- Atom* car;
- Atom* cdr;
- } cval;
- struct Atom {
- enum Tag {
- NIL, INT, REAL, STRING, SYMBOL, NATIVE, LAMBDA
- } tag;
- union {
- int64_t ival;
- double fval;
- Atom*(*native)(VM*, Cons*);
- Buffer buffer;
- Cons cons;
- };
- };
- struct VM {
- enum Builtin {
- NIL, CAR, CDR, APPLY, QUOTE, LAMBDA, DEF, DEFMACRO,
- ADD, SUB, MUL, DIV, MOD, INV,
- GT, LT, GTE, LTE, EQ, NE, NOT, T, F,
- GET, SET,
- };
- Atom* eval_tok(Token* tok);
- Atom* parse_list(Tokenizer* tokenizer);
- Atom* parse(const std::string& code);
- };
- #endif
- //.cpp
- #include "mylisp.hpp"
- struct Token {
- enum Type {
- LPAREN = '(', RPAREN = ')',
- QUOTE = '\'', QUASIQUOTE = '`', UNQUOTE = ',',
- INT, REAL, STRING = '"', SYMBOL,
- COMMENT = ';', SPACE = ' ', EOF
- } type;
- int line, col, pos;
- std::string::iterator begin, end;
- };
- void process_newline(std::string::iterator& it, int& line, int& col) {
- switch(*(it++)) {
- case '\r':
- if(it != end && *it == '\n') {
- ++it;
- }
- break;
- case '\n':
- case '\f':
- case '\v':
- break;
- default:
- ++col;
- return;
- }
- ++line;
- col = 0;
- }
- bool isident(char c) {
- if(c <= ' ') {
- return false;
- }
- switch(c) {
- case '(':
- case ')':
- case '\'':
- case '`':
- case ',':
- case '{':
- case ';':
- return false;
- }
- return true;
- }
- struct Tokenizer {
- int line, col, pos;
- std::string::iterator it, end;
- Tokenizer(std::string& code)
- :line(1), col(0), pos(0), it(code.begin(), end(code.end()) {}
- Token next() {
- std::string::iterator tokbegin = it;
- if(it == end) {
- return Token{EOF, line, col, pos, tokbegin, it};
- }
- switch(*(it++)) {
- case '(':
- tt = Token::LPAREN;
- break;
- case ')':
- tt = Token::RPAREN;
- break;
- case '\'':
- tt = Token::QUOTE;
- break;
- case '`':
- tt = Token::QUASIQUOTE;
- break;
- case ',':
- tt = Token::UNQUOTE;
- break;
- case '{':
- while(it != end && *it == '}') {
- ++col;
- ++pos;
- process_newline(*&it, *&line, *&col);
- }
- return Token{line, col, pos, tokbegin, it};
- case ';':
- while(it != end) {
- ++col;
- ++pos;
- process_newline(*&it, *&line, *&col);
- if(col == 0) {
- break;
- }
- }
- return Token{line, col, pos, tokbegin, it};
- default:
- if(*it <= ' ') {
- do {
- process_newline(*&it, *&line, *&col);
- } while(*it <= ' ');
- return Token{line, col, pos, tokbegin, it};
- }
- else {
- tokbegin = it;
- do {
- ++it;
- ++col;
- ++pos;
- } while(isident(*it));
- return Token{line, col, pos, tokbegin, it};
- }
- break;
- }
- }
- };
- Atom* VM::eval_tok(Token* tok) {
- switch(tok->type) {
- }
- }
- Atom* VM::read_list(Tokenizer* tokenizer, bool quasi) {
- Atom* root = nullptr;
- Atom** cur = &root;
- for(;;) {
- Token tok = tokenizer.next();
- switch(tok.type) {
- case Token::LPAREN:
- *cur = mkcons(read_list(tokenizer), builtin(NIL));
- break;
- case Token::RPAREN:
- return root;
- case Token::QUOTE:
- *cur = mkcons(builtin(QUOTE), read_atom(tokenizer));
- break;
- case Token::QUASIQUOTE:
- *cur = mkcons(builtin(QUOTE), read_atom(tokenizer, true));
- break;
- case Token::UNQUOTE:
- *cur = read_atom(tokenizer, quasi)->call(builtin(NIL));
- break;
- default:
- *cur = eval_tok(&tok);
- break;
- }
- cur = &cur->cdr;
- }
- }
- Atom* VM::read_atom(Tokenizer* tokenizer) {
- Token tok = tokenizer.next();
- switch(tok.type) {
- case Token::LPAREN:
- *cur = read_list(tokenizer);
- break;
- case Token::QUOTE:
- return quote(read_atom(tokenizer));
- }
- }
- Atom* VM::parse(const std::string& code) {
- Tokenizer tokenizer{code};
- Atom* root;
- std::vector<Atom**> path;
- path.push_back(&root);
- while(path.size()) {
- Token tok = tokenizer.next();
- switch(tok.type) {
- case Token::LPAREN:
- path.push_back(mkatom());
- break;
- case Token::EOF:
- return nullptr;
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement