303 lines
6.8 KiB
C++
303 lines
6.8 KiB
C++
#include "bed.h"
|
|
#include "internal/parser/parser.h"
|
|
|
|
namespace bed::internal::parser {
|
|
void Parser::locator(AddressPromise &addr) {
|
|
addr.base = AddressPromise::None{};
|
|
switch (peek()) {
|
|
case '.':
|
|
token(io::Token::AddressSymbol);
|
|
advance();
|
|
end_token();
|
|
addr.base = AddressPromise::Current{};
|
|
break;
|
|
case '$':
|
|
token(io::Token::AddressSymbol);
|
|
advance();
|
|
end_token();
|
|
addr.base = AddressPromise::Last{};
|
|
break;
|
|
case '%':
|
|
token(io::Token::AddressSymbol);
|
|
advance();
|
|
end_token();
|
|
addr.base = AddressPromise::LastRange{};
|
|
break;
|
|
case '[':
|
|
token(io::Token::AddressSymbol);
|
|
advance();
|
|
end_token();
|
|
addr.base = AddressPromise::Block{Direction::Backward};
|
|
break;
|
|
case ']':
|
|
token(io::Token::AddressSymbol);
|
|
advance();
|
|
end_token();
|
|
addr.base = AddressPromise::Block{Direction::Forward};
|
|
break;
|
|
case '^':
|
|
token(io::Token::AddressSymbol);
|
|
advance();
|
|
end_token();
|
|
addr.base = AddressPromise::Diagnostic{Direction::Backward};
|
|
break;
|
|
case '~':
|
|
token(io::Token::AddressSymbol);
|
|
advance();
|
|
end_token();
|
|
addr.base = AddressPromise::Diagnostic{Direction::Forward};
|
|
break;
|
|
case '\'':
|
|
token(io::Token::Mark);
|
|
advance();
|
|
if (('a' <= peek() && peek() <= 'z')
|
|
|| ('A' <= peek() && peek() <= 'Z'))
|
|
addr.base = AddressPromise::Mark{peek()};
|
|
else
|
|
throw ed_error("Valid mark needed after \'");
|
|
advance();
|
|
end_token();
|
|
break;
|
|
case '{': {
|
|
token(io::Token::AddressSymbol);
|
|
advance();
|
|
end_token();
|
|
uint16_t j = 0;
|
|
std::string func;
|
|
std::string arg;
|
|
token(io::Token::RubyFunction);
|
|
while (peek(j) != '}') {
|
|
if (peek(j) == '\0')
|
|
throw ed_error("Scripted address not terminated");
|
|
if (peek(j) == '\\')
|
|
++j;
|
|
if (peek(j) == ':') {
|
|
func = peek_str(j);
|
|
advance(j + 1);
|
|
end_token();
|
|
token(io::Token::RubyArg);
|
|
j = 0;
|
|
continue;
|
|
}
|
|
++j;
|
|
}
|
|
if (func.size())
|
|
arg = peek_str(j);
|
|
else
|
|
func = peek_str(j);
|
|
addr.base = AddressPromise::Scripted{std::move(func), std::move(arg)};
|
|
advance(j);
|
|
end_token();
|
|
token(io::Token::AddressSymbol);
|
|
advance();
|
|
end_token();
|
|
} break;
|
|
case '/': {
|
|
token(io::Token::Regexp);
|
|
advance();
|
|
uint64_t j = 0;
|
|
while (true) {
|
|
if (peek(j) == '\0')
|
|
break;
|
|
if (peek(j) == '/')
|
|
break;
|
|
else if (peek(j) == '\\')
|
|
j += 2;
|
|
else if (peek(j) == '[')
|
|
while (peek(j) != '\0' && cmd[i] != ']')
|
|
j++;
|
|
else
|
|
j++;
|
|
}
|
|
addr.base = AddressPromise::Regex(
|
|
Direction::Forward,
|
|
std::string(peek_str(j))
|
|
);
|
|
advance(j + 1);
|
|
end_token();
|
|
} break;
|
|
case '?': {
|
|
token(io::Token::Regexp);
|
|
advance();
|
|
uint16_t j = 0;
|
|
while (true) {
|
|
if (peek(j) == '\0')
|
|
break;
|
|
if (peek(j) == '?')
|
|
break;
|
|
else if (peek(j) == '\\')
|
|
j += 2;
|
|
else if (peek(j) == '[')
|
|
while (peek(j) != '\0' && cmd[i] != ']')
|
|
j++;
|
|
else
|
|
j++;
|
|
}
|
|
addr.base = AddressPromise::Regex(
|
|
Direction::Backward,
|
|
std::string(peek_str(j))
|
|
);
|
|
advance(j + 1);
|
|
end_token();
|
|
} break;
|
|
case '<': {
|
|
token(io::Token::Label);
|
|
advance();
|
|
uint16_t j = 0;
|
|
while (peek(j) != '>'
|
|
&& peek(j) != '<'
|
|
&& peek(j) != '\0')
|
|
j++;
|
|
switch (peek(j)) {
|
|
case '\0':
|
|
case '>':
|
|
addr.base = AddressPromise::SymbolDefinition{
|
|
std::string(peek_str(j))
|
|
};
|
|
break;
|
|
case '<':
|
|
addr.base = AddressPromise::SymbolReference{
|
|
Direction::Backward,
|
|
std::string(peek_str(j))
|
|
};
|
|
break;
|
|
}
|
|
advance(j + 1);
|
|
end_token();
|
|
} break;
|
|
case '>': {
|
|
token(io::Token::Label);
|
|
advance();
|
|
uint16_t j = 0;
|
|
while (peek(j) != '>' && peek(j) != '\0')
|
|
j++;
|
|
switch (peek(j)) {
|
|
case '\0':
|
|
throw ed_error("Unterminated symbol reference addressing.");
|
|
case '>':
|
|
addr.base = AddressPromise::SymbolReference{
|
|
Direction::Forward,
|
|
std::string(peek_str(j))
|
|
};
|
|
break;
|
|
}
|
|
advance(j + 1);
|
|
end_token();
|
|
} break;
|
|
case '+': {
|
|
token(io::Token::AddressSymbol);
|
|
advance();
|
|
end_token();
|
|
token(io::Token::Number);
|
|
addr.base = AddressPromise::Current{};
|
|
uint16_t j = 0;
|
|
uint64_t num = 0;
|
|
while ('0' <= peek(j) && peek(j) <= '9') {
|
|
num = num * 10 + (peek(j) - '0');
|
|
j++;
|
|
}
|
|
if (j == 0)
|
|
num = 1;
|
|
addr.offset += num;
|
|
advance(j);
|
|
end_token();
|
|
} break;
|
|
case '-': {
|
|
token(io::Token::AddressSymbol);
|
|
advance();
|
|
end_token();
|
|
token(io::Token::Number);
|
|
addr.base = AddressPromise::Current{};
|
|
uint16_t j = 0;
|
|
uint64_t num = 0;
|
|
while ('0' <= peek(j) && peek(j) <= '9') {
|
|
num = num * 10 + (peek(j) - '0');
|
|
j++;
|
|
}
|
|
if (j == 0)
|
|
num = 1;
|
|
addr.offset -= num;
|
|
advance(j);
|
|
end_token();
|
|
} break;
|
|
default:
|
|
if ('0' <= peek() && peek() <= '9') {
|
|
token(io::Token::Number);
|
|
uint64_t num = 0;
|
|
while ('0' <= peek() && peek() <= '9') {
|
|
num = num * 10 + (peek() - '0');
|
|
advance();
|
|
}
|
|
addr.base = AddressPromise::Number{num};
|
|
end_token();
|
|
}
|
|
}
|
|
}
|
|
|
|
int64_t Parser::offset() {
|
|
int64_t offset = 0;
|
|
while (peek() == '+' || peek() == '-'
|
|
|| ('0' <= peek() && peek() <= '9')) {
|
|
bool positive = peek() != '-';
|
|
token(io::Token::AddressSymbol);
|
|
if (peek() == '+' || peek() == '-')
|
|
advance();
|
|
end_token();
|
|
token(io::Token::Number);
|
|
uint16_t j = 0;
|
|
int64_t num = 0;
|
|
while ('0' <= peek(j) && peek(j) <= '9')
|
|
num = num * 10 + (peek(j++) - '0');
|
|
if (j == 0)
|
|
num = 1;
|
|
advance(j);
|
|
end_token();
|
|
offset += positive ? num : -num;
|
|
skip_ws();
|
|
}
|
|
skip_ws();
|
|
return offset;
|
|
}
|
|
|
|
void Parser::address(AddressPromise &addr) {
|
|
if (peek() == ':') {
|
|
token(io::Token::BufferName);
|
|
advance();
|
|
uint16_t j = 0;
|
|
while (peek(j) != ':' && peek(j) != '\0')
|
|
j++;
|
|
addr.bufname = peek_str(j);
|
|
advance(j);
|
|
if (peek() == ':')
|
|
advance();
|
|
end_token();
|
|
}
|
|
skip_ws();
|
|
if (peek() == '\0')
|
|
return;
|
|
locator(addr);
|
|
skip_ws();
|
|
addr.offset += offset();
|
|
}
|
|
|
|
void Parser::addresses(std::vector<AddressPromise> &addresses) {
|
|
skip_ws();
|
|
addresses.push_back({});
|
|
auto *addr = &addresses.back();
|
|
address(*addr);
|
|
while (peek() == ',' || peek() == ';') {
|
|
addr->jumping = peek() == ';';
|
|
token(io::Token::AddressSeperator);
|
|
advance();
|
|
skip_ws();
|
|
addresses.push_back({});
|
|
addr = &addresses.back();
|
|
address(*addr);
|
|
}
|
|
if (addresses.size() == 1
|
|
&& addr->offset == 0 && !addr->bufname.has_value()
|
|
&& std::holds_alternative<AddressPromise::None>(addr->base))
|
|
addresses.pop_back();
|
|
}
|
|
} // namespace bed::internal::parser
|