merlin-utils/script.re2c

325 lines
5.8 KiB
Plaintext
Raw Normal View History

2019-12-08 18:55:33 +00:00
/* link script support */
/*
label opcode operand
*/
#include <string>
#include <unordered_map>
#include <stdexcept>
#include <cctype>
#include <cstdint>
2019-12-15 00:01:12 +00:00
#include "script.h"
2019-12-08 18:55:33 +00:00
/*!re2c
re2c:define:YYCTYPE = char;
re2c:yyfill:enable = 0;
// :-~ includes ; which interferes with comments.
ident = [:<-~][0-~]*;
ws = [ \t];
eof = "\x00";
2019-12-15 00:01:12 +00:00
number_prefix = [%$0-9];
ident_prefix = [:-~];
string_prefix = ['"];
2019-12-08 18:55:33 +00:00
*/
2019-12-15 00:01:12 +00:00
namespace {
std::unordered_map<std::string, opcode_t> opcodes = {
#define x(op) { #op, OP_##op },
2019-12-08 18:55:33 +00:00
2019-12-15 00:01:12 +00:00
#include "ops.h"
#undef x
2019-12-08 18:55:33 +00:00
2019-12-15 00:01:12 +00:00
/* aliases */
{ "AUX", OP_ADR },
{ "REZ", OP_RES },
{ "LIN", OP_LNK },
{ "KIN", OP_KND },
{ "=", OP_EQ }
};
2019-12-08 18:55:33 +00:00
}
static int x_number_operand(const char *YYCURSOR) {
2019-12-15 00:01:12 +00:00
const char *iter = YYCURSOR;
// const char *YYMARKER = nullptr;
2019-12-08 18:55:33 +00:00
uint32_t rv = 0;
/*!re2c
* { throw std::invalid_argument("bad operand"); }
'%' [01]+ {
++iter;
for(;iter < YYCURSOR; ++iter) {
rv <<= 1;
rv |= *iter - '0';
}
goto exit;
}
'$' [A-Fa-f0-9]+ {
++iter;
for(;iter < YYCURSOR; ++iter) {
char c = *iter | 0x20;
rv <<= 4;
if (c <= '9') rv |= c - '0';
else rv |= c - 'a' + 10;
}
goto exit;
}
[0-9]+ {
for(;iter < YYCURSOR; ++iter) {
rv *= 10;
rv += *iter - '0';
}
goto exit;
}
*/
exit:
char c = *YYCURSOR;
if (isspace(c) || c == 0) return rv;
throw std::invalid_argument("bad operand");
}
2019-12-15 00:01:12 +00:00
static std::string x_label_operand(const char *YYCURSOR, bool insensitive) {
const char *iter = YYCURSOR;
// const char *YYMARKER = nullptr;
2019-12-08 18:55:33 +00:00
std::string rv;
/*!re2c
* { throw std::invalid_argument("bad operand"); }
ident {
2019-12-15 00:01:12 +00:00
rv = std::string(iter, YYCURSOR);
if (insensitive)
for (char &c : rv) rv = std::toupper(c);
goto exit;
2019-12-08 18:55:33 +00:00
}
*/
exit:
char c = *YYCURSOR;
2019-12-15 00:01:12 +00:00
if (isspace(c) || c == 0) {
//look up symbol, verify it's an absolute value, etc
return rv;
}
2019-12-08 18:55:33 +00:00
throw std::invalid_argument("bad operand");
}
static std::string x_string_operand(const char *YYCURSOR) {
2019-12-15 00:01:12 +00:00
const char *iter = YYCURSOR;
2019-12-08 18:55:33 +00:00
std::string rv;
/*!re2c
* { throw std::invalid_argument("bad operand"); }
['] [^']* ['] | ["] [^"]* ["] {
rv = std::string(iter+1, YYCURSOR-1);
goto exit;
}
*/
exit:
char c = *YYCURSOR;
if (isspace(c) || c == 0) return rv;
throw std::invalid_argument("bad operand");
}
2019-12-15 00:01:12 +00:00
uint32_t number_operand(const char *YYCURSOR, const std::unordered_map<std::string, uint32_t> &map, int flags) {
const char *cp = YYCURSOR;
// const char *YYMARKER = nullptr;
/*!re2c
* { throw std::invalid_argument("bad operand"); }
[;] | eof {
2019-12-15 00:01:12 +00:00
if (flags & OP_REQUIRED)
throw std::invalid_argument("missing operand");
return 0;
}
2019-12-08 18:55:33 +00:00
2019-12-15 00:01:12 +00:00
number_prefix {
return x_number_operand(cp);
}
2019-12-08 18:55:33 +00:00
2019-12-15 00:01:12 +00:00
ident_prefix {
std::string s = x_label_operand(cp, flags & OP_INSENSITIVE);
auto iter = map.find(s);
if (iter == map.end()) throw std::runtime_error("Bad symbol");
return iter->second;
}
*/
}
int ovr_operand(const char *YYCURSOR) {
2019-12-08 18:55:33 +00:00
int rv = 0;
2019-12-15 00:01:12 +00:00
const char *YYMARKER = nullptr;
2019-12-08 18:55:33 +00:00
/*!re2c
* { throw std::invalid_argument("bad operand"); }
[;] | eof {
2019-12-15 00:01:12 +00:00
return OVR_NONE;
2019-12-08 18:55:33 +00:00
}
'ALL' {
2019-12-15 00:01:12 +00:00
rv = OVR_ALL;
2019-12-08 18:55:33 +00:00
}
'OFF' {
2019-12-15 00:01:12 +00:00
rv = OVR_OFF;
2019-12-08 18:55:33 +00:00
}
*/
char c = *YYCURSOR;
if (isspace(c) || c == 0) return rv;
throw std::invalid_argument("bad operand");
}
2019-12-15 00:01:12 +00:00
std::string label_operand(const char *YYCURSOR, int flags) {
const char *cp = YYCURSOR;
// const char *YYMARKER = nullptr;
2019-12-08 18:55:33 +00:00
/*!re2c
* { throw std::invalid_argument("bad operand"); }
[;] | eof {
2019-12-15 00:01:12 +00:00
if (flags & OP_REQUIRED)
throw std::invalid_argument("missing operand");
return std::string();
2019-12-08 18:55:33 +00:00
}
2019-12-15 00:01:12 +00:00
ident_prefix {
return x_label_operand(cp, flags & OP_INSENSITIVE);
2019-12-08 18:55:33 +00:00
}
*/
}
2019-12-15 00:01:12 +00:00
std::string path_operand(const char *YYCURSOR, int flags) {
2019-12-08 18:55:33 +00:00
std::string rv;
2019-12-15 00:01:12 +00:00
const char *iter = YYCURSOR;
// const char *YYMARKER = nullptr;
2019-12-08 18:55:33 +00:00
/*!re2c
* { throw std::invalid_argument("bad operand"); }
2019-12-15 00:01:12 +00:00
[;] | eof {
2019-12-15 00:01:12 +00:00
if (flags & OP_REQUIRED)
throw std::invalid_argument("missing operand");
return rv;
2019-12-08 18:55:33 +00:00
}
2019-12-15 00:01:12 +00:00
string_prefix {
return x_string_operand(iter);
}
2019-12-08 18:55:33 +00:00
// don't allow leading quotes, eof, or comment chars
2019-12-15 00:01:12 +00:00
[^ \t\x00;*'"][^ \t\x00]* {
2019-12-08 18:55:33 +00:00
rv = std::string(iter, YYCURSOR);
goto exit;
}
*/
2019-12-15 00:01:12 +00:00
exit:
2019-12-08 18:55:33 +00:00
char c = *YYCURSOR;
if (isspace(c) || c == 0) return rv;
throw std::invalid_argument("bad operand");
}
2019-12-15 00:01:12 +00:00
std::string string_operand(const char *YYCURSOR, int flags) {
const char *cp = YYCURSOR;
// const char *YYMARKER = nullptr;
2019-12-08 18:55:33 +00:00
/*!re2c
* { throw std::invalid_argument("bad operand"); }
2019-12-15 00:01:12 +00:00
[;] | eof {
2019-12-15 00:01:12 +00:00
if (flags & OP_REQUIRED)
throw std::invalid_argument("missing operand");
return std::string();
}
string_prefix {
return x_string_operand(cp);
}
2019-12-08 18:55:33 +00:00
*/
}
2019-12-15 00:01:12 +00:00
void no_operand(const char *YYCURSOR) {
2019-12-08 18:55:33 +00:00
/*!re2c
* { throw std::invalid_argument("bad operand"); }
[;] | eof { return; }
2019-12-08 18:55:33 +00:00
*/
}
2019-12-15 00:01:12 +00:00
void parse_line(const char *YYCURSOR) {
2019-12-08 18:55:33 +00:00
2019-12-15 00:01:12 +00:00
label_t label;
opcode_t opcode = OP_NONE;
2019-12-08 18:55:33 +00:00
const char *iter = YYCURSOR;
2019-12-15 00:01:12 +00:00
const char *YYMARKER = nullptr;
2019-12-08 18:55:33 +00:00
/*!re2c
2019-12-15 00:01:12 +00:00
* { throw std::invalid_argument("bad label"); }
2019-12-08 18:55:33 +00:00
[;*] | eof {
return;
}
2019-12-15 00:01:12 +00:00
ws { goto opcode; }
2019-12-08 18:55:33 +00:00
ident / (ws|eof) {
2019-12-15 00:01:12 +00:00
label = std::string(iter, YYCURSOR);
2019-12-08 18:55:33 +00:00
goto opcode;
}
*/
opcode:
while (isspace(*YYCURSOR)) ++YYCURSOR;
iter = YYCURSOR;
/*!re2c
* { throw std::invalid_argument("bad opcode"); }
[;]|eof { return; }
2019-12-08 18:55:33 +00:00
2019-12-15 00:01:12 +00:00
'=' / (ws|eof) { opcode = OP_EQ; goto operand; }
2019-12-08 18:55:33 +00:00
[A-Za-z]+ / (ws|eof) {
2019-12-15 00:01:12 +00:00
size_t l = YYCURSOR - iter;
2019-12-08 18:55:33 +00:00
if (l > 3) l = 3;
std::string s(iter, iter + l);
2019-12-15 00:01:12 +00:00
for (char &c : s) c = std::toupper(c);
auto iter = opcodes.find(s);
if (iter == opcodes.end()) {
2019-12-08 18:55:33 +00:00
throw std::invalid_argument("bad opcode");
}
2019-12-15 00:01:12 +00:00
opcode = iter->second;
2019-12-08 18:55:33 +00:00
goto operand;
}
*/
operand:
while (isspace(*YYCURSOR)) ++YYCURSOR;
iter = YYCURSOR;
2019-12-15 00:01:12 +00:00
void evaluate(label_t label, opcode_t opcode, const char *);
2019-12-08 18:55:33 +00:00
2019-12-15 00:01:12 +00:00
evaluate(label, opcode, YYCURSOR);
2019-12-08 18:55:33 +00:00
}