|
|
|
/**
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|