mirror of
https://github.com/arabine/open-story-teller.git
synced 2025-12-06 17:09:06 +01:00
New parser for lines + constants (allow labels in constants)
This commit is contained in:
parent
263cc7986e
commit
bde25fd004
4 changed files with 113 additions and 115 deletions
|
|
@ -30,43 +30,14 @@ THE SOFTWARE.
|
|||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <string>
|
||||
|
||||
namespace Chip32
|
||||
{
|
||||
// =============================================================================
|
||||
// GLOBAL UTILITY FUNCTIONS
|
||||
// =============================================================================
|
||||
static const char* ws = " \t\n\r\f\v";
|
||||
|
||||
// trim from end of string (right)
|
||||
static inline std::string& rtrim(std::string& s, const char* t = ws)
|
||||
{
|
||||
s.erase(s.find_last_not_of(t) + 1);
|
||||
return s;
|
||||
}
|
||||
|
||||
// trim from beginning of string (left)
|
||||
static inline std::string& ltrim(std::string& s, const char* t = ws)
|
||||
{
|
||||
s.erase(0, s.find_first_not_of(t));
|
||||
return s;
|
||||
}
|
||||
|
||||
// trim from both ends of string (right then left)
|
||||
static inline std::string& trim(std::string& s, const char* t = ws)
|
||||
{
|
||||
return ltrim(rtrim(s, t), t);
|
||||
}
|
||||
|
||||
static std::vector<std::string> Split(const std::string &theString)
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
std::istringstream iss(theString);
|
||||
for(std::string s; iss >> s; )
|
||||
result.push_back(s);
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::string ToLower(const std::string &text)
|
||||
{
|
||||
std::string newText = text;
|
||||
|
|
@ -108,16 +79,6 @@ static bool IsOpCode(const std::string &label, OpCode &op)
|
|||
return success;
|
||||
}
|
||||
|
||||
static void GetArgs(Instr &instr, const std::string &data)
|
||||
{
|
||||
std::string value;
|
||||
std::istringstream iss(data);
|
||||
while (getline(iss, value, ','))
|
||||
{
|
||||
instr.args.push_back(trim(value));
|
||||
}
|
||||
}
|
||||
|
||||
static inline void leu32_put(std::vector<std::uint8_t> &container, uint32_t data)
|
||||
{
|
||||
container.push_back(data & 0xFFU);
|
||||
|
|
@ -144,6 +105,37 @@ static inline void leu16_put(std::vector<std::uint8_t> &container, uint16_t data
|
|||
m_lastError = ss.str(); \
|
||||
return false; } \
|
||||
|
||||
std::vector<std::string> Split(std::string line)
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
std::istringstream iss(line);
|
||||
std::string token;
|
||||
|
||||
while (std::getline(iss, token, ' ')) {
|
||||
// Vérifier si le jeton contient une virgule
|
||||
size_t comma_pos = token.find(",");
|
||||
if (comma_pos != std::string::npos) {
|
||||
// Diviser le jeton en deux parties séparées par la virgule
|
||||
std::string first_token = token.substr(0, comma_pos);
|
||||
std::string second_token = token.substr(comma_pos + 1);
|
||||
// Ajouter chaque partie au vecteur de résultats
|
||||
if (!first_token.empty()) {
|
||||
result.push_back(first_token);
|
||||
}
|
||||
if (!second_token.empty()) {
|
||||
result.push_back(second_token);
|
||||
}
|
||||
} else {
|
||||
// Ajouter le jeton entier au vecteur de résultats
|
||||
if (!token.empty()) {
|
||||
result.push_back(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// ASSEMBLER CLASS
|
||||
// =============================================================================
|
||||
|
|
@ -255,44 +247,52 @@ bool Assembler::CompileMnemonicArguments(Instr &instr)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Assembler::CompileConstantArguments(Instr &instr)
|
||||
bool Assembler::CompileConstantArgument(Instr &instr, const std::string &a)
|
||||
{
|
||||
for (auto &a : instr.args)
|
||||
instr.compiledArgs.clear(); instr.args.clear(); instr.useLabel = false;
|
||||
|
||||
// Check string
|
||||
if (a.size() > 2)
|
||||
{
|
||||
// Check string
|
||||
if (a.size() > 2)
|
||||
// Detected string
|
||||
if ((a[0] == '"') && (a[a.size() - 1] == '"'))
|
||||
{
|
||||
// Detected string
|
||||
if ((a[0] == '"') && (a[a.size() - 1] == '"'))
|
||||
for (int i = 1; i < (a.size() - 1); i++)
|
||||
{
|
||||
for (int i = 1; i < (a.size() - 1); i++)
|
||||
{
|
||||
instr.compiledArgs.push_back(a[i]);
|
||||
}
|
||||
instr.compiledArgs.push_back(0);
|
||||
continue;
|
||||
instr.compiledArgs.push_back(a[i]);
|
||||
}
|
||||
instr.compiledArgs.push_back(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
// here, we check if the intergers are correct
|
||||
uint32_t intVal = static_cast<uint32_t>(strtol(a.c_str(), NULL, 0));
|
||||
|
||||
bool sizeOk = false;
|
||||
if (((intVal <= UINT8_MAX) && (instr.dataTypeSize == 8)) ||
|
||||
((intVal <= UINT16_MAX) && (instr.dataTypeSize == 16)) ||
|
||||
((intVal <= UINT32_MAX) && (instr.dataTypeSize == 32))) {
|
||||
sizeOk = true;
|
||||
}
|
||||
CHIP32_CHECK(instr, sizeOk, "integer too high: " << intVal);
|
||||
if (instr.dataTypeSize == 8) {
|
||||
instr.compiledArgs.push_back(intVal);
|
||||
} else if (instr.dataTypeSize == 16) {
|
||||
leu16_put(instr.compiledArgs, intVal);
|
||||
} else {
|
||||
leu32_put(instr.compiledArgs, intVal);
|
||||
// Detect label
|
||||
else if (a[0] == '.')
|
||||
{
|
||||
// Label must be 32-bit, throw an error if not the case
|
||||
CHIP32_CHECK(instr, instr.dataTypeSize == 32, "Labels must be stored in a 32-bit area (DC32)")
|
||||
instr.useLabel = true;
|
||||
instr.args.push_back(a);
|
||||
leu32_put(instr.compiledArgs, 0); // reserve 4 bytes
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// here, we check if the intergers are correct
|
||||
uint32_t intVal = static_cast<uint32_t>(strtol(a.c_str(), NULL, 0));
|
||||
|
||||
bool sizeOk = false;
|
||||
if (((intVal <= UINT8_MAX) && (instr.dataTypeSize == 8)) ||
|
||||
((intVal <= UINT16_MAX) && (instr.dataTypeSize == 16)) ||
|
||||
((intVal <= UINT32_MAX) && (instr.dataTypeSize == 32))) {
|
||||
sizeOk = true;
|
||||
}
|
||||
CHIP32_CHECK(instr, sizeOk, "integer too high: " << intVal);
|
||||
if (instr.dataTypeSize == 8) {
|
||||
instr.compiledArgs.push_back(intVal);
|
||||
} else if (instr.dataTypeSize == 16) {
|
||||
leu16_put(instr.compiledArgs, intVal);
|
||||
} else {
|
||||
leu32_put(instr.compiledArgs, intVal);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -336,19 +336,14 @@ bool Assembler::Parse(const std::string &data)
|
|||
lineNum++;
|
||||
Instr instr;
|
||||
instr.line = lineNum;
|
||||
|
||||
line = trim(line);
|
||||
|
||||
int pos = line.find_first_of(";");
|
||||
if (pos != std::string::npos) {
|
||||
line.erase(pos);
|
||||
}
|
||||
|
||||
if (line.length() <= 0) continue;
|
||||
if (std::all_of(line.begin(), line.end(), ::isspace)) continue;
|
||||
|
||||
// Split the line
|
||||
std::vector<std::string> lineParts = Split(line);
|
||||
|
||||
CHIP32_CHECK(instr, (lineParts.size() > 0), " not a valid line");
|
||||
|
||||
// Ok until now
|
||||
|
|
@ -384,12 +379,7 @@ bool Assembler::Parse(const std::string &data)
|
|||
}
|
||||
else if ((instr.code.nbAargs > 0) && (lineParts.size() >= 2))
|
||||
{
|
||||
// Compute arguments
|
||||
for (int i = 1; i < lineParts.size(); i++)
|
||||
{
|
||||
GetArgs(instr, lineParts[i]);
|
||||
}
|
||||
|
||||
instr.args.insert(instr.args.begin(), lineParts.begin() + 1, lineParts.end());
|
||||
CHIP32_CHECK(instr, instr.args.size() == instr.code.nbAargs,
|
||||
"Bad number of parameters. Required: " << static_cast<int>(instr.code.nbAargs) << ", got: " << instr.args.size());
|
||||
nbArgsSuccess = true;
|
||||
|
|
@ -402,7 +392,6 @@ bool Assembler::Parse(const std::string &data)
|
|||
if (nbArgsSuccess)
|
||||
{
|
||||
CHIP32_CHECK(instr, CompileMnemonicArguments(instr) == true, "Compile failure");
|
||||
|
||||
instr.addr = code_addr;
|
||||
code_addr += 1 + instr.compiledArgs.size();
|
||||
m_instructions.push_back(instr);
|
||||
|
|
@ -430,23 +419,27 @@ bool Assembler::Parse(const std::string &data)
|
|||
|
||||
if (instr.isRomData)
|
||||
{
|
||||
instr.addr = code_addr;
|
||||
m_labels[opcode] = instr; // location of the start of the data
|
||||
// if ROM data, we generate one instruction per argument
|
||||
// reason: arguments may be labels, easier to replace later
|
||||
|
||||
for (int i = 2; i < lineParts.size(); i++)
|
||||
{
|
||||
GetArgs(instr, lineParts[i]);
|
||||
CHIP32_CHECK(instr, CompileConstantArgument(instr, lineParts[i]), "Compile argument error, stopping.");
|
||||
m_instructions.push_back(instr);
|
||||
code_addr += instr.compiledArgs.size();
|
||||
instr.addr = code_addr;
|
||||
}
|
||||
CHIP32_CHECK(instr, CompileConstantArguments(instr), "Compile error, stopping.");
|
||||
|
||||
instr.addr = code_addr;
|
||||
code_addr += instr.compiledArgs.size();
|
||||
}
|
||||
else // RAM DATA
|
||||
else // RAM DATA, only one argument is used: the size of the array
|
||||
{
|
||||
instr.addr = ram_addr;
|
||||
instr.dataLen = static_cast<uint16_t>(strtol(lineParts[2].c_str(), NULL, 0));
|
||||
ram_addr += instr.dataLen;
|
||||
m_labels[opcode] = instr;
|
||||
m_instructions.push_back(instr);
|
||||
}
|
||||
m_labels[opcode] = instr;
|
||||
m_instructions.push_back(instr);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ private:
|
|||
std::string m_lastError;
|
||||
|
||||
std::vector<Instr> m_instructions;
|
||||
bool CompileConstantArguments(Instr &instr);
|
||||
bool CompileConstantArgument(Instr &instr, const std::string &a);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,14 +58,14 @@ struct DebugContext
|
|||
for (std::vector<Chip32::Instr>::const_iterator iter = assembler.Begin();
|
||||
iter != assembler.End(); ++iter)
|
||||
{
|
||||
if (iter->isRomCode())
|
||||
if (iter->isRomCode() || iter->isRomData)
|
||||
{
|
||||
qDebug() << "-------------------";
|
||||
qDebug() << "Instr: " << iter->mnemonic.c_str();
|
||||
qDebug() << "Addr: " << Qt::hex << iter->addr;
|
||||
qDebug() << "Line: " << iter->line;
|
||||
qDebug() << "\t- Opcode: " << Qt::hex << iter->code.opcode
|
||||
<< ", Args: " << iter->code.bytes;
|
||||
<< ", opcode args: " << iter->code.bytes;
|
||||
|
||||
int i = 1;
|
||||
for (auto arg : iter->compiledArgs)
|
||||
|
|
|
|||
|
|
@ -5,13 +5,19 @@ static const std::string test1 = R"(
|
|||
jump .entry
|
||||
|
||||
; Constant elements are separated by commas
|
||||
$imageBird DC8 "example.bmp", 8 ; string of chars, followed by one byte
|
||||
$soundChoice DC8 "choose1.snd"
|
||||
$someConstant DC32 12456789
|
||||
$imageBird DC8, "example.bmp", 8 ; string of chars, followed by one byte
|
||||
$soundChoice DC8, "choose1.snd"
|
||||
$yaya DC8, "yaya.bmp"
|
||||
$rabbit DC8, "rabbit.bmp"
|
||||
$someConstant DC32, 12456789
|
||||
|
||||
; Liste des labels
|
||||
$ChoiceObject DC32, .MEDIA_02, .MEDIA_03
|
||||
|
||||
; DVsxx to declare a variable in RAM, followed by the number of elements
|
||||
$MyArray DV8 10 ; array of 10 bytes
|
||||
$RamData1 DV32 1 ; one 32-bit integer
|
||||
$MyArray DV8, 10 ; array of 10 bytes
|
||||
$RamData1 DV32, 1 ; one 32-bit integer
|
||||
$ChoiceMem DV32, 10 ; 10 elements for the choices, to be generated
|
||||
|
||||
; label definition
|
||||
.entry: ;; comment here should work
|
||||
|
|
@ -22,13 +28,16 @@ $RamData1 DV32 1 ; one 32-bit integer
|
|||
lcons r1, $soundChoice ; set to 0 if no sound
|
||||
syscall 1
|
||||
|
||||
mov r1, sp ; save sp address in R1 (first element)
|
||||
lcons r0, .MEDIA_02
|
||||
push r0
|
||||
; We put all the choices in reserved global memory
|
||||
lcons t2, 4 ; address increment
|
||||
lcons t0, $ChoiceMem
|
||||
lcons t1, .MEDIA_02
|
||||
store @t0, t1, 4 ; @t0 = t1
|
||||
|
||||
lcons r0, .MEDIA_03
|
||||
push r0
|
||||
lcons r2, 3 ; 3 iterations
|
||||
jump .media
|
||||
lcons r2, 2 ; 3 iterations
|
||||
jump .media ; no return possible, so a jump is enough
|
||||
|
||||
; Generic media choice manager
|
||||
.media:
|
||||
|
|
@ -51,30 +60,26 @@ $RamData1 DV32 1 ; one 32-bit integer
|
|||
.media_loop:
|
||||
sub t0, t1 ; i--
|
||||
add t4, t3 ; @++
|
||||
skipnz r0 ; if (r0) goto start_loop;
|
||||
skipnz t0 ; if (r0) goto start_loop;
|
||||
jump .media_loop_start
|
||||
push sp
|
||||
push r0
|
||||
push r1
|
||||
load r0, @r4, 4
|
||||
load r0, @t4, 4 ; r0 = content in ram at address in T4
|
||||
call r0
|
||||
pop r1
|
||||
pop r0
|
||||
pop sp
|
||||
|
||||
; TODO: wait for event
|
||||
|
||||
; TODO: if ok event, free stack, then
|
||||
|
||||
jump .media_loop
|
||||
|
||||
.MEDIA_02:
|
||||
lcons r0, $imageBird ; image name address in ROM located in R0 (null terminated)
|
||||
lcons r0, $yaya ; image name address in ROM located in R0 (null terminated)
|
||||
lcons r1, $soundChoice ; set to 0 if no sound
|
||||
syscall 1
|
||||
ret
|
||||
|
||||
.MEDIA_03:
|
||||
lcons r0, $imageBird ; image name address in ROM located in R0 (null terminated)
|
||||
lcons r1, $soundChoice ; set to 0 if no sound
|
||||
lcons r0, $rabbit
|
||||
lcons r1, $soundChoice
|
||||
syscall 1
|
||||
ret
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue