aboutsummaryrefslogtreecommitdiffstats
path: root/parser.cpp
blob: 317bc872e5d15bfdc0b1501dad4fead542f54601 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
/**
 * forspll - LLVM-based Forsp compiler
 * Copyright (C) 2024  Clyne Sullivan <clyne@bitgloo.com>
 *
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#include "parser.hpp"

#include <cctype>
#include <iostream>

std::string name;

static bool isname(char ch) {
    return !isspace(ch) && ch != ')';
}

static std::string_view extractName(std::string_view sv)
{
    name.clear();

    while (!sv.empty()) {
        const auto ch = sv.front();

        if (isname(ch)) {
            name += ch;
            sv.remove_prefix(1);
        } else {
            break;
        }
    }

    return sv;
}

std::pair<std::string_view, Token> nextToken(std::string_view sv)
{
    if (sv.empty())
        return {sv, Token::none};

    while (std::isspace(sv.front()))
        sv.remove_prefix(1);

    if (sv.empty())
        return {sv, Token::none};

    const auto ch = sv.front();
    if (ch == ';') {
        return {{}, Token::none};
    } else if (ch == '(') {
        return {sv.substr(1), Token::ThunkOpen};
    } else if (ch == ')') {
        return {sv.substr(1), Token::ThunkClose};
    } else if (ch == '\'') {
        return {extractName(sv.substr(1)), Token::Quote};
    } else if (ch == '$') {
        return {extractName(sv.substr(1)), Token::PopVar};
    } else if (ch == '^') {
        return {extractName(sv.substr(1)), Token::PushVar};
    } else if (isdigit(ch) || (ch == '-' && sv.size() > 1 && isdigit(sv[1]))) {
        return {extractName(sv), Token::Number};
    } else if (ch == '\\' && sv.size() > 1) {
        name = std::to_string(static_cast<int>(sv[1]));
        return {sv.substr(2), Token::Number};
    } else if (isname(ch)) {
        return {extractName(sv), Token::Var};
    }

    return {sv, Token::none};
}

void printToken(Token tok)
{
    switch (tok) {
    case Token::ThunkOpen:
        std::cout << "ThunkOpen ";
        break;
    case Token::ThunkClose:
        std::cout << "ThunkClose ";
        break;
    case Token::Quote:
        std::cout << "Quote ";
        break;
    case Token::PopVar:
        std::cout << "PopVar ";
        break;
    case Token::PushVar:
        std::cout << "PushVar ";
        break;
    case Token::Var:
        std::cout << "Var ";
        break;
    case Token::Number:
        std::cout << "Number ";
        break;
    case Token::none:
        //std::cout << "none ";
        break;
    }
}