URL
https://opencores.org/ocsvn/forwardcom/forwardcom/trunk
Subversion Repositories forwardcom
Compare Revisions
- This comparison shows the changes necessary to convert path
/forwardcom
- from Rev 41 to Rev 42
- ↔ Reverse comparison
Rev 41 → Rev 42
/bintools/assem2.cpp
0,0 → 1,1797
/**************************** assem2.cpp ******************************** |
* Author: Agner Fog |
* Date created: 2017-04-17 |
* Last modified: 2021-08-11 |
* Version: 1.11 |
* Project: Binary tools for ForwardCom instruction set |
* Module: assem.cpp |
* Description: |
* Module for assembling ForwardCom .as files. |
* This module contains: |
* - expression(): Interpretation of expressions containing operators and |
* any type of operands. |
* Copyright 2017-2021 GNU General Public License http://www.gnu.org/licenses |
******************************************************************************/ |
#include "stdafx.h" |
|
|
// Interpret and evaluate expression |
SExpression CAssembler::expression(uint32_t tok1, uint32_t maxtok, uint32_t options) { |
// tok1: index to first token, |
// maxtok: maximum number of tokens to use, |
// options: 0: normal, |
// 1: unsigned |
// 2: inside []. interpret as memory operand |
// 4: interpret option = keyword |
// 8: inside {}. has no meaning yet |
// 0x10: check syntax and count tokens, but do not call functions or report numeric |
// overflow, wrong operand types, or unknown names |
|
// This function scans the tokens and finds the operator with lowest priority. |
// The function is called recursively for each operand to this operator. |
// The level of parantheses is saved in the brackets stack. |
// The scanning terminates at any of these conditions: |
// * a token that cannot be part of the expression is encountered |
// * all tokens are used |
// * a comma is encountered |
// * an unmatched end bracket is encountered |
|
uint32_t tok; // current token |
uint32_t toklow = tok1; // operator with lowest priority |
uint32_t tokcolon = 0; // matching triadic operator with lowest priority |
uint32_t ntok = 0; // number of tokens used |
uint32_t priority = 0; // priority of this operator |
uint32_t bracketlevel = 0; // number of brackets in stack |
uint32_t state = 0; // 0: expecting value, 1: after value, expecting operator or end |
uint32_t i; // loop counter |
uint32_t temp; // temporary result |
uint32_t tokid; // token.id |
int32_t symi; // symbol index |
bool is_local = false; // symbol is local constant |
uint8_t endbracket; // expected end bracket |
|
SExpression exp1, exp2; // expressions during evaluation |
zeroAllMembers(exp1); // reset exp1 |
exp1.tokens = 1; |
|
for (tok = tok1; tok < tok1 + maxtok; tok++) { |
if (lineError) {exp1.etype = 0; return exp1;} |
if (tokens[tok].type == TOK_OPR) { |
// operator found. search for brackets |
if (tokens[tok].priority == 1 || tokens[tok].priority == 14) { |
// bracket found. ?: operator treated as bracket here |
switch (tokens[tok].id) { |
case '?': |
if (tokens[tok].priority > priority && bracketlevel == 0) { // if multiple ?:, split by the last one |
priority = tokens[tok].priority; toklow = tok; |
} |
// continue in next case |
case '(': case '[': case '{': // opening bracket. push on bracket stack |
brackets.push(uint8_t(tokens[tok].id)); |
bracketlevel++; |
state = 0; |
break; |
case ')': case ']': case '}': case ':': // closing bracket |
if (bracketlevel == 0) { |
goto EXIT_LOOP; // this end bracket is not part of the expression. |
} |
// remove matching opening bracket from stack |
bracketlevel--; |
endbracket = brackets.pop(); |
switch (endbracket) { |
case '(': endbracket = ')'; break; |
case '[': endbracket = ']'; break; |
case '{': endbracket = '}'; break; |
case '?': endbracket = ':'; break; |
} |
if (endbracket != tokens[tok].id) { |
// end bracket does not match begin bracket |
errors.report(tokens[tok].pos, tokens[tok].stringLength, ERR_BRACKET_END); |
goto EXIT_LOOP; |
} |
if (tokens[tok].id == ':') { |
if (bracketlevel == 0 && priority == 14 && tokcolon == 0) { |
tokcolon = tok; // ':' matches current '?' with lowest priority |
} |
state = 0; |
continue; |
} |
state = 1; |
continue; // finished with this token |
} |
} |
if (bracketlevel) continue; // don't search for priority inside brackets |
|
if (state == 1) { |
// expecting operator |
if (tokens[tok].id == ';') break; // end at semicolon |
if (tokens[tok].id == ',' && !(options & 2)) break; // end at comma, except inside [] |
if (tokens[tok].id == '=' && !(options & 6)) break; // end at =, except inside [] or when interpreting option = value |
|
if (tokens[tok].priority >= priority) { // if multiple operators with same priority, split by the last one to get the first evaluated first |
// operator with lower priority found |
priority = tokens[tok].priority; |
toklow = tok; |
} |
if (tokens[tok].priority == 3) state = 1; else state = 0; // state 0 except after monadic operator |
} |
else if (state == 0 && (tokens[tok].id == '-' || tokens[tok].id == '+' || tokens[tok].priority == 3)) { |
// monadic operator |
if (priority < 3) { |
priority = 3; toklow = tok; |
} |
} |
else { |
errors.report(tokens[tok]); break; // unexpected operator |
} |
} |
else { |
// not an operator |
if (bracketlevel) continue; // inside brackets: search only for end bracket |
if (state == 0) { |
// expecting value |
switch (tokens[tok].type) { |
case TOK_NAM: case TOK_LAB: case TOK_VAR: case TOK_SEC: |
case TOK_NUM: case TOK_FLT: case TOK_CHA: case TOK_STR: |
case TOK_REG: case TOK_SYM: case TOK_XPR: case TOK_OPT: |
state = 1; // allowed value tokens |
break; |
case TOK_TYP: |
state = 1; // type expression |
break; |
case TOK_HLL: |
if (tokens[tok].id == HLL_FALSE || tokens[tok].id == HLL_TRUE) { |
state = 1; |
} |
else { |
errors.report(tokens[tok]); |
} |
break; |
default: |
errors.report(tokens[tok]); break; |
} |
} |
else { |
break; // no operator found after value. end here |
} |
} |
} |
EXIT_LOOP: |
if (lineError) {exp1.etype = 0; return exp1;} |
// number of tokens used |
ntok = tok - tok1; |
exp1.tokens = ntok; |
if (bracketlevel) { |
endbracket = brackets.pop(); |
errors.report(tokens[tok1].pos, tokens[tok].pos - tokens[tok1].pos, endbracket == '?' ? ERR_QUESTION_MARK : ERR_BRACKET_BEGIN); |
if (exp1.etype == 0) exp1.etype = XPR_INT; |
return exp1; |
} |
if (ntok == 0) { // no expression found |
if (maxtok == 0 && tok > 0) tok--; |
errors.report(tokens[tok].pos, tokens[tok].stringLength, ERR_MISSING_EXPR); |
return exp1; |
} |
|
switch (priority) { |
case 0: // no operator found. just an expression |
if (ntok > 2 && tokens[tok1].type == TOK_OPR && tokens[tok1].priority == 1) { |
// this is an expression in brackets |
uint32_t option1 = options; |
if (tokens[tok1].id == '[') { |
if (options & 2) errors.report(tokens[tok1]); // nested [[]] not allowed |
option1 |= 2; |
} |
if (tokens[tok1].id == '{') option1 |= 8; |
// evaluate expression inside bracket |
exp1 = expression(tok1 + 1, ntok - 2, option1); |
exp1.tokens += 2; |
goto RETURNEXP1; |
} |
else if (ntok == 1) { |
// this is a single token. get value |
switch (tokens[tok1].type) { |
case TOK_LAB: case TOK_VAR: case TOK_SEC: case TOK_SYM: |
exp1.etype = XPR_SYM1; // symbol address |
exp1.sym3 = tokens[tok1].id; |
symi = findSymbol(exp1.sym3); |
// is symbol local with known value? |
is_local = symi > 0 && symbols[symi].st_bind == STB_LOCAL && (symbols[symi].st_type == STT_CONSTANT || symbols[symi].st_type == STT_VARIABLE); |
if (options & 2) { // symbol inside [] |
exp1.etype |= XPR_MEM; |
exp1.sym3 = 0; |
if (is_local) { |
exp1.offset_mem = tokens[tok1].value.w;// don't take value from symbol, it may change |
exp1.etype &= ~XPR_SYM1; // symbol reference no longer needed |
exp1.etype |= XPR_OFFSET; // has offset |
} |
else { |
exp1.sym1 = tokens[tok1].id; |
} |
if (exp1.etype & (XPR_FLT | XPR_STRING)) { // float or string not allowed in memory operand |
errors.report(tokens[tok1].pos, tokens[tok1].stringLength, ERR_WRONG_TYPE); |
} |
} |
else { // symbol outside [] |
if (is_local) { |
if (symbols[symi].st_other & STV_FLOAT) exp1.etype |= XPR_FLT; |
else exp1.etype |= XPR_INT; |
exp1.value.i = tokens[tok1].value.u; // don't take value from symbol, it may change |
if (symbols[symi].st_other & STV_STRING) { |
exp1.etype = XPR_STRING; |
exp1.sym2 = (uint32_t)symbols[symi].st_unitnum; // sym2 used for string length |
} |
else { |
exp1.etype &= ~XPR_SYM1; // symbol reference no longer needed |
exp1.sym3 = 0; |
} |
} |
else { |
exp1.etype |= XPR_INT; // type not known yet? |
exp1.sym3 = tokens[tok1].id; |
} |
} |
break; |
case TOK_NUM: |
if (options & 2) { // number inside [] is offset |
exp1.etype = XPR_OFFSET; // integer value |
exp1.offset_mem = (int32_t)interpretNumber((char*)buf()+tokens[tok1].pos, tokens[tok1].stringLength, &temp); |
} |
else { // number outside [] is operand |
exp1.etype = XPR_INT; // integer value |
exp1.value.i = interpretNumber((char*)buf() + tokens[tok1].pos, tokens[tok1].stringLength, &temp); |
} |
if (temp) errors.report(tokens[tok1]); |
break; |
case TOK_FLT: |
exp1.etype = XPR_FLT; // floating point value |
exp1.value.d = interpretFloat((char*)buf()+tokens[tok1].pos, tokens[tok1].stringLength); |
if (options & 2) { // float not allowed in memory operand |
errors.report(tokens[tok1].pos, tokens[tok1].stringLength, ERR_WRONG_TYPE); |
} |
break; |
case TOK_CHA: { // character(s). convert to integer |
exp1.etype = XPR_INT; |
exp1.value.u = 0; |
bool escape = false; // check for \ escape characters |
int j = 0; // count characters |
for (i = 0; i < tokens[tok1].stringLength; i++) { |
uint8_t c = get<uint8_t>(tokens[tok1].pos + i); |
if (c == '\\' && !escape) { |
escape = true; continue; // escape next character |
} |
if (escape) { // special escape characters |
switch (c) { |
case '\\': break; |
case 'n': c = '\n'; break; |
case 'r': c = '\r'; break; |
case 't': c = '\t'; break; |
case '0': c = 0; break; |
} |
} |
escape = false; |
exp1.value.u += uint64_t(c) << j*8; |
j++; |
} |
if (options & 2) { // string not allowed in memory operand |
errors.report(tokens[tok1].pos, tokens[tok1].stringLength, ERR_WRONG_TYPE); |
} |
break;} |
case TOK_STR: { // string |
exp1.etype = XPR_STRING; |
exp1.value.u = stringBuffer.dataSize(); // save position of string |
exp1.sym2 = tokens[tok1].stringLength; // string length |
bool escape = false; // check for \ escape characters |
for (i = 0; i < tokens[tok1].stringLength; i++) { |
char c = get<char>(tokens[tok1].pos + i); |
if (c == '\\' && !escape) { |
escape = true; continue; // escape next character |
} |
if (escape) { // special escape characters |
switch (c) { |
case '\\': escape = false; break; |
case 'n': c = '\n'; break; |
case 'r': c = '\r'; break; |
case 't': c = '\t'; break; |
case '0': c = 0; break; |
} |
} |
if (escape && exp1.sym2) exp1.sym2--; // reduce length |
stringBuffer.put(c); |
escape = false; |
} |
stringBuffer.put(char(0)); // terminate string |
if (options & 2) { // string not allowed in memory operand |
errors.report(tokens[tok1].pos, tokens[tok1].stringLength, ERR_WRONG_TYPE); |
} |
break;} |
case TOK_REG: |
if (options & 2) { // register inside [] is base register |
exp1.etype = XPR_BASE | XPR_MEM; |
exp1.base = uint8_t(tokens[tok1].id); |
if ((tokens[tok1].id & 0xFE0) == REG_SPEC) { |
exp1.base = tokens[tok1].id >> 16; // special register. to do: check if register type is valid |
} |
} |
else { // normal register operand |
exp1.etype = XPR_REG | XPR_REG1; |
exp1.reg1 = tokens[tok1].id; |
} |
break; |
case TOK_NAM: |
if ((options & 0x10) == 0) errors.report(tokens[tok1]); |
exp1.etype |= XPR_UNRESOLV; // unresolved name |
break; |
case TOK_OPT: |
exp1.etype = XPR_OPTION; |
if ((tokens[tok1].id) == OPT_SCALAR) { |
exp1.etype |= XPR_SCALAR; |
} |
else { |
exp1.value.u = tokens[tok1].id; |
} |
break; |
case TOK_XPR: // expression |
if (tokens[tok1].value.u < expressions.numEntries()) { |
exp1 = expressions[tokens[tok1].value.w]; |
exp1.tokens = ntok; |
if ((exp1.etype & XPR_REG) && !(exp1.etype & XPR_MEM) && (options & 2)) { // register inside [] is base register |
exp1.etype = XPR_BASE | XPR_MEM; |
exp1.base = exp1.reg1; |
exp1.reg1 = 0; |
} |
} |
else errors.report(tokens[tok1]); |
break; |
case TOK_TYP: |
exp1.etype = XPR_TYPENAME; |
exp1.value.u = tokens[tok1].id; |
break; |
case TOK_HLL: |
if (tokens[tok1].id == HLL_FALSE || tokens[tok1].id == HLL_TRUE) { // translate to constant |
exp1.etype = XPR_INT; |
exp1.value.u = tokens[tok1].id & 1; |
} |
else { |
errors.report(tokens[tok1]); |
} |
break; |
default: |
errors.report(tokens[tok1]); |
} |
if (options & 2) exp1.etype |= XPR_MEM; // inside [], interpret as memory operand |
goto RETURNEXP1; |
} |
else { |
// unrecognized token |
errors.report(tokens[tok1]); |
} |
break; |
|
case 3: // monadic operator |
if (toklow == tok1) { // operator comes first |
exp1 = expression(toklow + 1, maxtok - 1, options); // evaluate the rest |
if (exp1.etype & XPR_UNRESOLV) { |
exp1.tokens++; // unresolved expression. return unresolved result |
goto RETURNEXP1; |
} |
zeroAllMembers(exp2); // zero exp2 |
switch (tokens[toklow].id) { |
case '+': // value is unchanged |
exp1.tokens++; |
goto RETURNEXP1;; // value is unchanged |
case '-': |
if (exp1.etype & (XPR_OP | XPR_REG | XPR_MEM)) { |
exp1 = op1minus(exp1); // convert -(A+B) etc. |
goto RETURNEXP1; |
} |
exp2 = exp1; // convert -A to 0-A |
exp1.tokens = 0; |
exp1.etype = XPR_INT; |
exp1.value.i = 0; |
tokid = '-'; |
break; // continue in dyadic operators with 0-exp2 |
case '!': |
exp1.tokens++; |
if (exp1.instruction == II_COMPARE |
&& (exp1.etype & XPR_REG1) && (exp1.etype & (XPR_REG2 | XPR_INT | XPR_IMMEDIATE))) { |
// compare instruction. invert condition |
exp1.optionbits ^= 1; |
exp1.etype |= XPR_OPTIONS; |
if ((exp1.reg1 & REG_V) && (dataType & TYP_FLOAT)) exp1.optionbits ^= 8; // floating point compare. invert gives unordered |
goto RETURNEXP1; |
} |
if (exp1.instruction == II_AND |
&& (exp1.etype & XPR_REG1) && (exp1.etype & XPR_INT)) { |
// test_bit/test_bits_or/jump instruction. invert condition |
exp1.optionbits ^= 4; |
exp1.etype |= XPR_OPTIONS; |
goto RETURNEXP1; |
} |
if (exp1.instruction == II_TEST_BITS_AND && (exp1.etype & XPR_REG1) && (exp1.etype & XPR_INT)) { |
// test_bits_and/jump instruction. invert condition |
exp1.optionbits ^= 1; |
exp1.etype |= XPR_OPTIONS; |
goto RETURNEXP1; |
} |
if (exp1.etype & (XPR_MEM | XPR_REG)) { // '!' ambiguous on register and memory operands |
errors.report(tokens[toklow].pos, tokens[toklow].stringLength, ERR_NOT_OP_AMBIGUOUS); |
} |
exp2.tokens = 0; |
exp2.etype = XPR_INT; |
exp2.value.i = 0; |
tokid = '='+D2; |
break; // continue in dyadic operators with exp1 == 0 |
case '~': |
exp2.tokens = 0; |
exp2.etype = XPR_INT; |
exp2.value.i = -1; |
tokid = '^'; |
break; // continue in dyadic operators with exp1 ^ -1 |
default: |
errors.report(tokens[tok1]); // ++ and -- not supported in expression |
return exp1; |
} |
goto DYADIC; // proceed to dyadic operator |
} |
else { // postfix ++ and -- |
errors.report(tokens[tok1+1]); // ++ and -- not supported in expression |
} |
goto RETURNEXP1; |
|
case 14: // triadic operator ?: |
// evaluate exp1 ? exp2 : exp3 for all expression types |
return op3(tok1, toklow, tokcolon, maxtok, options); |
|
default:; // continue below for dyadic operator |
} |
// dyadic operator. evaluate two subexpressions |
exp1 = expression(tok1, toklow - tok1, options); // evaluate fist expression |
if (exp1.tokens != toklow - tok1) errors.report(tokens[tok1 + exp1.tokens]); |
if (lineError) return exp1; |
|
exp2 = expression(toklow + 1, tok1 + maxtok - (toklow + 1), options); // evaluate second expression |
ntok = toklow - tok1 + 1 + exp2.tokens; |
tokid = tokens[toklow].id; // operator id |
if (lineError) return exp1; |
|
DYADIC: |
exp1 = op2(tokid, exp1, exp2); |
|
RETURNEXP1: |
if (lineError) return exp1; |
if (exp1.etype & XPR_ERROR) { |
errors.report(tokens[toklow].pos, tokens[toklow].stringLength, exp1.value.w); |
} |
return exp1; |
} |
|
// Interpret dyadic expression with any type of operands |
SExpression CAssembler::op2(uint32_t op, SExpression & exp1, SExpression & exp2) { |
|
if ((exp1.etype | exp2.etype) & XPR_UNRESOLV) { |
exp1.etype = XPR_UNRESOLV; // unresolved operand. make unresolved result |
exp1.tokens += exp2.tokens + 1; |
} |
else if ((exp1.etype & exp2.etype & XPR_MEM) |
//&& ((exp1.etype|exp2.etype) & (XPR_BASE|XPR_INDEX|XPR_OPTION|XPR_SYM1|XPR_SYM2|XPR_LIMIT|XPR_LENGTH|XPR_BROADC)) |
) { |
exp1 = op2Memory(op, exp1, exp2); // generation of memory operand. both operands inside [] and contain not only constants |
} |
else if (exp1.etype == XPR_OPTION && op == '=') { |
// option = value is handled by op2Memory |
exp1 = op2Memory(op, exp1, exp2); |
} |
else if (exp1.etype & exp2.etype & XPR_SYM1) { |
// adding or subtracting symbols and integers |
exp1 = op2Memory(op, exp1, exp2); |
} |
else if ((exp1.etype & XPR_SYM2) && (exp2.etype & XPR_INT)) { |
// (sym1-sym2)/const |
exp1 = op2Memory(op, exp1, exp2); |
} |
// generation of instruction involving registers and/or memory operand: |
// (don't rely on XPR_MEM flag here because we would catch expressions involving constants only inside [] ) |
//!else if ((exp1.etype | exp2.etype) & (XPR_REG | XPR_BASE /*| XPR_SYM1*/)) { |
// else if ((exp1.etype | exp2.etype) & (XPR_REG | XPR_BASE | XPR_SYM1)) { //?? |
else if (((exp1.etype | exp2.etype) & (XPR_REG | XPR_BASE)) || (exp1.sym1 | exp2.sym1)) { //?? |
exp1 = op2Registers(op, exp1, exp2); |
} |
else if ((exp1.etype | exp2.etype) & XPR_STRING) { |
exp1 = op2String(op, exp1, exp2); // string operation |
} |
else if ((exp1.etype & 0xF) == XPR_FLT || (exp2.etype & 0xF) == XPR_FLT) { |
// dyadic operators for float // floating point operation |
exp1 = op2Float(op, exp1, exp2); |
} |
else if ((exp1.etype & 0xF) == XPR_INT && (exp2.etype & 0xF) == XPR_INT) { |
// dyadic operators for integers // integer operation |
exp1 = op2Int(op, exp1, exp2); |
} |
else { |
// other types |
exp1.etype = XPR_ERROR; |
exp1.value.u = ERR_WRONG_TYPE; |
} |
return exp1; |
} |
|
// Interpret dyadic expression with integer operands |
SExpression CAssembler::op2Int(uint32_t op, SExpression const & exp1, SExpression const & exp2) { |
SExpression expr = exp1; |
expr.tokens = exp1.tokens + exp2.tokens + 1; |
switch (op & ~OP_UNS) { |
case '+': |
expr.value.u = exp1.value.u + exp2.value.u; |
break; |
case '-': |
expr.value.u = exp1.value.u - exp2.value.u; |
break; |
case '*': |
expr.value.i = exp1.value.i * exp2.value.i; |
break; |
case '/': |
if (exp2.value.i == 0) { |
expr.etype |= XPR_ERROR; |
expr.value.u = ERR_OVERFLOW; |
break; |
} |
if (op & OP_UNS) expr.value.u = exp1.value.u / exp2.value.u; // unsigned division |
else expr.value.i = exp1.value.i / exp2.value.i; // signed division |
break; |
case '%': |
if (exp2.value.i == 0) { |
expr.etype |= XPR_ERROR; |
expr.value.u = ERR_OVERFLOW; |
break; |
} |
if (op & OP_UNS) expr.value.u = exp1.value.u % exp2.value.u; // unsigned modulo |
else expr.value.i = exp1.value.i % exp2.value.i; // signed modulo |
break; |
case '<' + D2: // << |
expr.value.u = exp1.value.u << exp2.value.u; |
break; |
case '>' + D2: // >> shift right signed |
if (op & OP_UNS) expr.value.u = exp1.value.u >> exp2.value.u; // unsigned shift right |
else expr.value.i = exp1.value.i >> exp2.value.i; // signed shift right |
break; |
case '>' + D3: // >>> unsigned shift right |
expr.value.u = exp1.value.u >> exp2.value.u; |
break; |
case '<': // < compare |
if (op & OP_UNS) expr.value.i = exp1.value.u < exp2.value.u; // unsigned compare |
else expr.value.i = exp1.value.i < exp2.value.i; // signed compare |
break; |
case '<' + EQ: // <= compare |
if (op & OP_UNS) expr.value.i = exp1.value.u <= exp2.value.u; // unsigned compare |
else expr.value.i = exp1.value.i <= exp2.value.i; // signed compare |
break; |
case '>': // > compare |
if (op & OP_UNS) expr.value.i = exp1.value.u > exp2.value.u; // unsigned compare |
else expr.value.i = exp1.value.i > exp2.value.i; // signed compare |
break; |
case '>' + EQ: // >= compare |
if (op & OP_UNS) expr.value.i = exp1.value.u >= exp2.value.u; // unsigned compare |
else expr.value.i = exp1.value.i >= exp2.value.i; // signed compare |
break; |
case '=' + D2: // == |
expr.value.u = exp1.value.u == exp2.value.u; |
break; |
case '!' + EQ: // != |
expr.value.u = exp1.value.u != exp2.value.u; |
break; |
case '&': // bitwise and |
expr.value.u = exp1.value.u & exp2.value.u; |
break; |
case '|': // bitwise or |
expr.value.u = exp1.value.u | exp2.value.u; |
break; |
case '^': // bitwise xor |
expr.value.u = exp1.value.u ^ exp2.value.u; |
break; |
case '&' + D2: // logical and |
expr.value.u = exp1.value.u && exp2.value.u; |
break; |
case '|' + D2: // logical or |
expr.value.u = exp1.value.u || exp2.value.u; |
break; |
case '^' + D2: // logical xor |
expr.value.u = (exp1.value.u != 0) ^ (exp2.value.u != 0); |
break; |
default: // unsupported operator |
expr.etype |= XPR_ERROR; |
expr.value.u = ERR_WRONG_TYPE; |
} |
return expr; |
} |
|
// Interpret dyadic expression with floating point operands |
SExpression CAssembler::op2Float(uint32_t op, SExpression & exp1, SExpression & exp2) { |
SExpression expr = exp1; |
expr.tokens = exp1.tokens + exp2.tokens + 1; |
if (exp1.etype == XPR_INT) { // convert exp1 to float |
exp1.value.d = (double)exp1.value.i; |
expr.etype = XPR_FLT; |
} |
if (exp2.etype == XPR_INT) { // convert exp2 to float |
exp2.value.d = (double)exp2.value.i; |
expr.etype = XPR_FLT; |
} |
// dyadic operator on float |
switch (op) { |
case '+': |
expr.value.d = exp1.value.d + exp2.value.d; |
break; |
case '-': |
expr.value.d = exp1.value.d - exp2.value.d; |
break; |
case '*': |
expr.value.d = exp1.value.d * exp2.value.d; |
break; |
case '/': |
if (exp2.value.d == 0.) { |
expr.etype |= XPR_ERROR; |
expr.value.u = ERR_OVERFLOW; |
break; |
} |
expr.value.d = exp1.value.d / exp2.value.d; |
break; |
case '<': // signed compare |
expr.value.i = exp1.value.d < exp2.value.d; |
expr.etype = XPR_INT; |
break; |
case '<' + EQ: // <= signed compare |
expr.value.i = exp1.value.d <= exp2.value.d; |
expr.etype = XPR_INT; |
break; |
case '>': // signed compare |
expr.value.i = exp1.value.d > exp2.value.d; |
expr.etype = XPR_INT; |
break; |
case '>' + EQ: // >= signed compare |
expr.value.i = exp1.value.d <= exp2.value.d; |
expr.etype = XPR_INT; |
break; |
case '=' + D2: // == |
expr.value.i = exp1.value.d == exp2.value.d; |
expr.etype = XPR_INT; |
break; |
case '!' + EQ: // != |
expr.value.i = exp1.value.d != exp2.value.d; |
expr.etype = XPR_INT; |
break; |
case '&' + D2: // logical and |
expr.value.i = exp1.value.d != 0. && exp2.value.d != 0.; |
expr.etype = XPR_INT; break; |
break; |
case '|' + D2: // logical or |
expr.value.i = exp1.value.d != 0. || exp2.value.d != 0.; |
expr.etype = XPR_INT; break; |
break; |
default: // unsupported operator |
expr.etype |= XPR_ERROR; |
expr.value.u = ERR_WRONG_TYPE; |
} |
return expr; |
} |
|
// Interpret dyadic expression with register or memory operands, generating instruction |
SExpression CAssembler::op2Registers(uint32_t op, SExpression const & ex1, SExpression const & ex2) { |
SExpression expr = {{0}}; // return expression |
uint8_t swapped = false; // operands are swapped |
uint8_t cannotSwap = false; // cannot swap operands because both contain vector registers |
uint32_t i; // loop counter |
|
// make array of the two expressions |
SExpression exp12[2]; // copy of expressions |
uint32_t numtokens = ex1.tokens + ex2.tokens + 1; // number of tokens |
expr.tokens = numtokens; |
|
// resolve nested expressions |
if ((ex1.etype | ex2.etype) & XPR_OP) { |
/* |
if (op == '&' && (ex1.etype & XPR_REG) && !(ex1.etype & XPR_OP) && ex2.instruction == II_XOR && ((ex2.etype & 0xF) == XPR_INT) && ex2.value.i == -1) { |
// A & (B ^ -1) = and_not(A,B). This instruction is removed |
expr = ex1; expr.tokens = numtokens; |
expr.etype |= XPR_OP; |
expr.instruction = II_AND_NOT; |
expr.reg2 = ex2.reg1; |
return expr; |
} */ |
// simplify both expressions if possible |
exp12[0] = ex1; exp12[1] = ex2; |
for (i = 0; i < 2; i++) { |
if ((exp12[i].etype & (XPR_REG | XPR_MEM)) && (exp12[i].etype & XPR_IMMEDIATE) && exp12[i].value.i == 0) { |
if (exp12[i].instruction == II_SUB_REV) { |
// expression is -A converted to (0-A). change to register and sign bit |
exp12[i].etype &= ~(XPR_OPTIONS | XPR_IMMEDIATE | XPR_OP); |
exp12[i].instruction = 0; |
exp12[i].optionbits = 1; |
} |
else if (exp12[i].instruction == II_MUL_ADD && exp12[i].value.i == 0) { |
// expression is -A*B converted to (-A*B+0). change to A*B and sign bit |
exp12[i].instruction = II_MUL; |
exp12[i].optionbits = exp12[i].optionbits & 1; |
exp12[i].etype &= ~(XPR_OPTIONS | XPR_IMMEDIATE); |
} |
else if (exp12[i].instruction == II_ADD_ADD && (exp12[i].etype & (XPR_INT | XPR_FLT)) && (exp12[i].optionbits & 3) == 3 && exp12[i].value.i == 0) { |
// expression is -(A+B) converted to (-A-B+0). change to A+B and sign bit |
exp12[i].etype &= ~(XPR_INT | XPR_FLT); |
exp12[i].instruction = II_ADD; |
exp12[i].optionbits ^= 3; |
exp12[i].etype &= ~(XPR_OPTIONS | XPR_IMMEDIATE); |
} |
} |
else if (exp12[i].instruction == II_SUB_REV) { |
// change -A+B to -(A-B) |
exp12[i].instruction = II_SUB; |
exp12[i].optionbits ^= 3; |
} |
} |
if ((exp12[0].etype & XPR_IMMEDIATE) && (exp12[1].etype & XPR_IMMEDIATE)) { |
// both operands contain an immediate. combine the immediates if possible |
|
bool isfloat[2]; // check if operands are float |
for (i = 0; i < 2; i++) isfloat[i] = (exp12[i].etype & XPR_IMMEDIATE) == XPR_FLT; |
|
// convert integer to float if the other operand is float |
for (i = 0; i < 2; i++) { |
if (isfloat[1-i] && !isfloat[i]) { |
exp12[i].value.d = (double)exp12[i].value.i; |
isfloat[i] = true; |
} |
} |
|
if (op == '+' || op == '-') { // add or subtract operands and store in exp12[1] |
uint8_t sign = 0; |
switch (exp12[0].instruction) { |
case II_ADD: case II_SUB_REV: |
sign = exp12[0].optionbits >> 1 & 1; |
if (op == '-') sign ^= 1; |
break; |
case II_SUB: |
sign = (exp12[0].optionbits >> 1 & 1) ^ 1; |
if (op == '-') sign ^= 1; |
break; |
case II_ADD_ADD: |
sign = exp12[0].optionbits >> 2 & 1; |
if (op == '-') sign ^= 1; |
break; |
default: // no other instructions can be combined with + or - |
expr.etype |= XPR_ERROR; expr.value.u = ERR_WRONG_OPERANDS; |
return expr; |
} |
if (exp12[1].instruction == II_SUB) sign ^= 1; |
|
// add immediates and store them in exp12[1] |
if (sign) { |
if (isfloat[1]) exp12[1].value.d -= exp12[0].value.d; |
else exp12[1].value.i -= exp12[0].value.i; |
} |
else { |
if (isfloat[1]) exp12[1].value.d += exp12[0].value.d; |
else exp12[1].value.i += exp12[0].value.i; |
} |
exp12[0].value.i = 0; |
exp12[0].etype &= ~ (XPR_INT | XPR_FLT); |
if (exp12[0].instruction == II_ADD_ADD) { |
exp12[0].instruction = II_ADD; |
exp12[0].optionbits &= ~ 4; |
} |
else { |
exp12[0].instruction = 0; |
} |
} |
else if (op == '*' && exp12[0].instruction == II_MUL) { |
if (isfloat[0]) { |
exp12[1].value.d *= exp12[0].value.d; |
} |
else { |
exp12[1].value.i *= exp12[0].value.i; |
} |
exp12[0].value.i = 0; |
exp12[0].etype &= ~ (XPR_INT | XPR_FLT | XPR_OP); |
exp12[0].instruction = 0; |
} /* |
else if (op == '&' && exp12[0].instruction == II_AND && !isfloat[0]) { |
exp12[1].value.i &= exp12[0].value.i; |
exp12[0].value.i = 0; |
exp12[0].etype &= ~ XPR_INT; |
exp12[0].instruction = 0; |
} |
else if (op == '|' && exp12[0].instruction == II_OR && !isfloat[0]) { |
exp12[1].value.i |= exp12[0].value.i; |
exp12[0].value.i = 0; |
exp12[0].etype &= ~ XPR_INT; |
exp12[0].instruction = 0; |
} |
else if (op == '^' && exp12[0].instruction == II_XOR && !isfloat[0]) { |
exp12[1].value.i ^= exp12[0].value.i; |
exp12[0].value.i = 0; |
exp12[0].etype &= ~ XPR_INT; |
exp12[0].instruction = 0; |
} */ |
else { |
expr.etype |= XPR_ERROR; expr.value.u = ERR_WRONG_OPERANDS; |
} |
} |
|
// error if two memory operands |
uint32_t etyp0 = exp12[0].etype, etyp1 = exp12[1].etype; |
//if ((etyp0 & etyp1 & XPR_MEM) || (exp12[0].value.i && exp12[1].value.i)) { |
if (etyp0 & etyp1 & XPR_MEM) { |
expr.etype |= XPR_ERROR; expr.value.u = ERR_WRONG_OPERANDS; |
return expr; |
} |
|
// error if too many operands |
if (((etyp0 & XPR_REG1) != 0) + ((etyp0 & XPR_REG2) != 0) + ((etyp0 & XPR_REG3) != 0) |
+ ((etyp1 & XPR_REG1) != 0) + ((etyp1 & XPR_REG2) != 0) + ((etyp1 & XPR_REG3) != 0) |
+ (((etyp0 | etyp1) & XPR_MEM) != 0) + (((etyp0 | etyp1) & XPR_IMMEDIATE) != 0) > 3) { |
expr.etype |= XPR_ERROR; expr.value.u = ERR_TOO_MANY_OPERANDS; |
return expr; |
} |
|
// check which operations can swap |
if (op != '+' && op != '*' && op != '&' && op != '|' && op != '^' && op != '-') { |
cannotSwap = true; // operation is not commutative ('-' is handled with sign bits) |
} |
|
// put operands in this order: register, memory, immediate |
if ((exp12[0].etype & (XPR_IMMEDIATE | XPR_MEM)) && !(exp12[1].etype & XPR_IMMEDIATE) && !cannotSwap) { |
// first operand is immediate or memory, and second operant is not immediate |
// swap operands if not two vector registers |
if (exp12[0].reg1 & exp12[1].reg1 & REG_V) { |
// both operands contain a vector register. cannot swap. make error message later if swapping required |
cannotSwap = true; |
} |
else if ((exp12[1].etype & XPR_MEM) && op == '*') { |
// second operand also contains memory |
cannotSwap = true; |
} |
else { // swap operands to get immediate or memory operand last |
expr = exp12[0]; exp12[0] = exp12[1]; exp12[1] = expr; |
if (op == '-') { |
op = '+'; // convert '-' to '+' and flip sign bit to make operation commutative |
exp12[0].optionbits ^= 1; |
} |
swapped = true; |
} |
} |
|
if (op == '+' || op == '-') { |
/* done above: |
if (exp12[0].etype & (XPR_IMMEDIATE | XPR_MEM) && exp12[1].instruction == II_MUL && !(exp12[1].etype & (XPR_INT | XPR_FLT))) { |
// (memory or constant) + reg*reg. swap operands |
expr = exp12[0]; exp12[0] = exp12[1]; exp12[1] = expr; |
if (op == '-') { |
exp12[0].optionbits ^= 1; // invert signs in both operands |
exp12[1].optionbits ^= 1; |
} |
} */ |
if (!((exp12[0].etype | exp12[1].etype) & XPR_OP)) { |
// +/-R1 +/-R2 |
if (op == '-') exp12[1].optionbits ^= 1; // sign of second operand |
// change sign of constant if this simplifies it |
if ((exp12[1].etype & XPR_INT) && (exp12[1].optionbits & 1)) { |
exp12[1].value.i = -exp12[1].value.i; |
exp12[1].optionbits = 0; |
} |
else if ((exp12[1].etype & XPR_FLT) && (exp12[1].optionbits & 1)) { |
exp12[1].value.d = -exp12[1].value.d; |
exp12[1].optionbits = 0; |
} |
uint8_t s = exp12[0].optionbits | exp12[1].optionbits << 1; // combine signs |
expr = exp12[1]; expr.tokens = numtokens; |
expr.reg1 = exp12[0].reg1; |
if (exp12[1].etype & XPR_REG1) { |
expr.reg2 = exp12[1].reg1; expr.etype |= XPR_REG2; |
} |
expr.etype |= XPR_OP | XPR_REG1; |
expr.optionbits = 0; |
switch (s) { |
case 0: // R1 + R2 |
expr.instruction = II_ADD; break; |
case 1: // -R1 + R2 |
expr.instruction = II_SUB_REV; break; |
case 2: // R1 - R2 |
expr.instruction = II_SUB; break; |
case 3: // -R1 -R2 |
expr.instruction = II_ADD_ADD; |
expr.value.i = 0; |
expr.optionbits = s; |
expr.etype |= XPR_INT | XPR_OPTIONS; |
break; |
} |
return expr; |
} |
else if (exp12[0].instruction == II_MUL || exp12[1].instruction == II_MUL) { |
// (A*B)+C |
if (op == '-') exp12[1].optionbits ^= 1; // change sign if '-' |
if (exp12[1].instruction == II_MUL) { // swap expressions if A+(B*C) |
if (exp12[0].reg1 & REG_V) { |
expr.etype |= XPR_ERROR; |
expr.value.w = ERR_CANNOT_SWAP_VECT; // cannot put vector addend as first operand |
return expr; |
} |
expr = exp12[0]; exp12[0] = exp12[1]; exp12[1] = expr; // swap expressions |
} |
expr = exp12[0] | exp12[1]; // combine expressions |
expr.tokens = numtokens; |
if ((exp12[0].etype & exp12[1].etype & (XPR_MEM|XPR_IMMEDIATE)) || // two memory or two immediate operands |
((exp12[0].etype & (XPR_MEM|XPR_IMMEDIATE)) == (XPR_MEM|XPR_IMMEDIATE))) { // exp12[0] has both memory and immediate |
expr.etype |= XPR_ERROR; |
expr.value.w = ERR_TOO_COMPLEX; |
return expr; |
} |
expr.instruction = II_MUL_ADD; |
expr.etype |= XPR_OPTIONS; |
if (((exp12[0].etype & XPR_MEM) && !(exp12[1].etype & XPR_IMMEDIATE)) || (exp12[0].etype & XPR_IMMEDIATE)) { |
expr.instruction = II_MUL_ADD2; // get A*C+B |
// we don't need to do anything with signs here because the sign options apply to product and addend, not to specific operands |
} |
expr.etype |= XPR_OP; |
expr.reg1 = exp12[0].reg1; expr.reg2 = exp12[0].reg2; |
if (exp12[1].etype & XPR_REG) { // C has a register |
if (exp12[0].etype & XPR_REG2) { // 3 registers |
expr.reg3 = exp12[1].reg1; |
expr.etype |= XPR_REG3; |
} |
else { |
expr.reg2 = exp12[1].reg1; // 2 registers |
expr.etype |= XPR_REG2; |
} |
} |
// optionbits 0-1 = sign of product. optionbits 2-3 = sign of addend. |
expr.optionbits = 3 * (exp12[0].optionbits & 1) | 0xC * (exp12[1].optionbits & 1); |
expr.etype |= XPR_OPTIONS; |
return expr; |
} |
else if (exp12[0].instruction == II_ADD || exp12[0].instruction == II_SUB) { |
// (A+B)+C |
expr = exp12[0] | exp12[1]; // combine expressions |
expr.tokens = numtokens; |
expr.reg1 = exp12[0].reg1; |
expr.etype |= XPR_OP; |
expr.instruction = II_ADD_ADD; |
|
if ((exp12[0].etype & XPR_IMMEDIATE) || ((exp12[0].etype & XPR_MEM) && !(exp12[1].etype & XPR_IMMEDIATE))) { |
// does not fit |
expr.etype |= XPR_ERROR; |
expr.value.w = cannotSwap ? ERR_CANNOT_SWAP_VECT : ERR_TOO_COMPLEX; |
return expr; |
} |
|
if (exp12[1].etype & XPR_REG) { // C has a register |
if (exp12[0].etype & XPR_REG2) { // 3 registers |
expr.reg3 = exp12[1].reg1; |
expr.etype |= XPR_REG3; |
} |
else if (exp12[0].etype & XPR_REG1) { // 2 registers |
expr.reg2 = exp12[1].reg1; |
expr.etype |= XPR_REG2; |
} |
else { |
expr.reg1 = exp12[1].reg1; // 1 registers |
expr.etype |= XPR_REG1; |
} |
} |
expr.optionbits = (exp12[0].optionbits & 3) | ((exp12[1].optionbits & 1) ^ (op == '-')) << 2; |
if (exp12[0].instruction == II_SUB) expr.optionbits ^= 2; |
if (swapped && op == '-') expr.optionbits ^= 7; |
expr.etype |= XPR_OPTIONS; |
return expr; |
|
} |
else if (exp12[1].instruction == II_ADD || exp12[1].instruction == II_SUB) { |
// A+(B+C) |
expr = exp12[0] | exp12[1]; // combine expressions |
expr.tokens = numtokens; |
expr.reg1 = exp12[0].reg1; |
expr.etype |= XPR_OP; |
expr.instruction = II_ADD_ADD; |
|
if (exp12[0].etype & exp12[1].etype & (XPR_IMMEDIATE | XPR_MEM)) { |
// does not fit |
expr.etype |= XPR_ERROR; |
expr.value.w = ERR_TOO_COMPLEX; |
return expr; |
} |
|
if (exp12[0].etype & XPR_MEM) { |
// A = mem, B = register, C = immediate. Needs additional reordering |
expr.optionbits = ((exp12[1].optionbits & 1) ^ (op == '-')) // register into first place |
| (exp12[0].optionbits & 1) << 1 // memory in second place |
| ((exp12[1].optionbits >> 1 & 1) ^ (op == '-')) << 2; // immediate in third place |
if (exp12[1].instruction == II_SUB) expr.optionbits ^= 4; |
if (swapped && op == '-') expr.optionbits ^= 7; |
expr.reg1 = exp12[1].reg1; |
expr.etype |= XPR_OPTIONS; |
return expr; |
} |
|
|
if (exp12[1].etype & XPR_REG2) { |
// 3 registers |
expr.reg2 = exp12[1].reg1; |
expr.reg3 = exp12[1].reg2; |
expr.etype |= XPR_REG2 | XPR_REG3; |
} |
else if (exp12[1].etype & XPR_REG1) { |
// 2 registers |
expr.reg2 = exp12[1].reg1; |
expr.etype |= XPR_REG2; |
} |
|
expr.optionbits = (exp12[0].optionbits & 1) | 6 * ((exp12[1].optionbits & 1) ^ (op == '-')); |
if (exp12[1].instruction == II_SUB) expr.optionbits ^= 4; |
if (swapped && op == '-') expr.optionbits ^= 7; |
expr.etype |= XPR_OPTIONS; |
return expr; |
} |
} |
else if (!((exp12[0].etype | exp12[1].etype) & XPR_OP) |
&& (op == '*' || (op == '/' && !swapped))) { |
// (+/- a) * (+/- b) |
expr = exp12[0] | exp12[1]; |
expr.etype |= XPR_OP; |
expr.tokens = numtokens; |
expr.optionbits = exp12[0].optionbits ^ exp12[1].optionbits; |
if (expr.optionbits & 1) { // change sign |
if ((exp12[1].etype & 0xF) == XPR_FLT) { |
expr.value.d = -exp12[1].value.d; |
expr.optionbits = 0; |
} |
else if ((exp12[1].etype & 0xF) == XPR_INT) { |
expr.value.i = -exp12[1].value.i; |
expr.optionbits = 0; |
} |
else if (/*(exp12[1].etype & XPR_REG) &&*/ op == '*' && expr.value.i == 0) { |
// change -a*b to -a*b + 0 |
expr.instruction = II_MUL_ADD; |
expr.optionbits = 0x3; |
expr.reg1 = exp12[0].reg1; |
if (exp12[1].etype & XPR_REG1) { |
expr.reg2 = exp12[1].reg1; expr.etype |= XPR_REG2; |
} |
expr.etype |= XPR_INT | XPR_OPTIONS; |
return expr; |
} |
else { |
expr.etype |= XPR_ERROR; expr.value.w = ERR_TOO_COMPLEX; |
return expr; |
} |
} |
expr.reg1 = exp12[0].reg1; |
if (exp12[1].etype & XPR_REG1) { |
expr.reg2 = exp12[1].reg1; expr.etype |= XPR_REG2; |
} |
expr.instruction = (op == '*') ? II_MUL : II_DIV; |
return expr; |
} |
|
else if (((exp12[0].etype & exp12[1].etype) & XPR_INT) |
&& (op == '='+D2 || op == '!'+EQ) |
&& exp12[0].value.i == exp12[1].value.i |
&& ((exp12[0].etype | exp12[1].etype) & (XPR_REG1 | XPR_REG2)) == XPR_REG1 |
&& (exp12[0].etype & exp12[1].etype & XPR_REG1) == 0) { |
// (r1 & const) == const gives test_bits_and |
expr = exp12[0] | exp12[1]; |
expr.etype |= XPR_OP | XPR_OPTIONS; |
expr.tokens = numtokens; |
expr.instruction = II_TEST_BITS_AND; |
if (op == '!'+EQ) expr.optionbits ^= 1; |
return expr; |
} |
else if (op == '&'+D2 || op == '|'+D2 || op == '^' || op == '^'+D2) { |
// possible combination of compare or test with extra boolean operand |
int swap = exp12[1].instruction != 0; |
expr = exp12[swap]; |
if (expr.instruction == II_COMPARE && exp12[1-swap].etype == (XPR_REG | XPR_REG1)) { |
// use fallback register as an extra boolean operand on compare instruction |
switch (op & 0xFF) { |
case '&': |
expr.optionbits |= 0x10; break; |
case '|': |
expr.optionbits |= 0x20; break; |
case '^': |
expr.optionbits |= 0x30; break; |
default: |
expr.etype |= XPR_ERROR; expr.value.u = ERR_TOO_COMPLEX; |
} |
expr.etype |= XPR_OP | XPR_OPTIONS | XPR_FALLBACK; |
expr.tokens = numtokens; |
expr.fallback = exp12[1-swap].reg1; |
return expr; |
} |
/*else if (expr.instruction >= II_TEST_BIT && expr.instruction <= II_TEST_BITS_OR && exp12[1-swap].etype == (XPR_REG | XPR_REG1)) { |
// Use fallback register as an extra boolean operand on bit test instructions |
// This does not work yet. test_bit cannot be expressed with high level operators |
switch (op & 0xFF) { |
case '&': |
expr.optionbits |= 0x01; break; |
case '|': |
expr.optionbits |= 0x02; break; |
case '^': |
expr.optionbits |= 0x03; break; |
default: |
expr.etype |= XPR_ERROR; expr.value.u = ERR_TOO_COMPLEX; |
} |
expr.etype |= XPR_OP | XPR_OPTIONS | XPR_FALLBACK; |
expr.tokens = numtokens; |
expr.fallback = exp12[1-swap].reg1; |
return expr; |
}*/ |
} |
} |
|
// not a complex expression |
if ((ex1.etype & (XPR_IMMEDIATE | XPR_MEM)) && !((ex1.reg1 & REG_V) || (ex2.etype & XPR_IMMEDIATE))){ |
// first operand is integer, float or memory. swap operands if not two vector registers or memory and immediate |
exp12[0] = ex2; exp12[1] = ex1; swapped = true; |
} |
else { |
exp12[0] = ex1; exp12[1] = ex2; |
} |
expr.etype |= (exp12[1].etype & XPR_REG1) << 1; // XPR_REG1 becomes XPR_REG2 |
|
// combine everything from the two operands |
expr = exp12[0] | exp12[1]; |
expr.etype |= XPR_OP; |
expr.tokens = numtokens; |
expr.reg1 = exp12[0].reg1; |
expr.reg2 = exp12[1].reg1; |
expr.etype |= (exp12[1].etype & XPR_REG1) << 1; |
|
if (expr.instruction) { |
expr.etype |= XPR_ERROR; expr.value.u = ERR_TOO_COMPLEX; |
return expr; |
} |
// 2-operand instruction |
switch (op) { |
case '+': |
expr.instruction = II_ADD; break; |
case '-': |
expr.instruction = swapped ? II_SUB_REV : II_SUB; break; |
case '*': |
expr.instruction = II_MUL; break; |
case '/': |
expr.instruction = swapped ? II_DIV_REV : II_DIV; break; |
case '%': |
if (swapped) {expr.etype |= XPR_ERROR; expr.value.u = ERR_WRONG_TYPE;} |
expr.instruction = II_REM; break; |
case '&': case '&'+D2: // boolean AND and bitwise AND have same implementation |
expr.instruction = II_AND; break; |
case '|': case '|'+D2: // boolean OR and bitwise OR have same implementation |
expr.instruction = II_OR; break; |
case '^': case '^'+D2: |
expr.instruction = II_XOR; break; |
case '<': |
expr.instruction = II_COMPARE; |
expr.optionbits = 2 ^ swapped; |
expr.etype |= XPR_OPTIONS; |
break; |
case '<' + EQ: // <= |
expr.instruction = II_COMPARE; |
expr.optionbits = 5 ^ swapped; |
expr.etype |= XPR_OPTIONS; |
break; |
case '>': |
expr.instruction = II_COMPARE; |
expr.optionbits = 4 ^ swapped; |
expr.etype |= XPR_OPTIONS; |
break; |
case '>' + EQ: // >= |
expr.instruction = II_COMPARE; |
expr.optionbits = 3 ^ swapped; |
expr.etype |= XPR_OPTIONS; |
break; |
case '='+D2: // == |
expr.instruction = II_COMPARE; |
expr.optionbits = 0; |
//expr.etype |= XPR_OPTIONS; |
break; |
case '!'+EQ: // != |
expr.instruction = II_COMPARE; |
expr.etype |= XPR_OPTIONS; |
expr.optionbits = 1; // compare for not equal |
if ((expr.reg1 & REG_V) && (dataType & TYP_FLOAT)) { |
expr.optionbits |= 8; // floating point not equal includes unordered |
} |
break; |
case '<' + D2: // << |
if (swapped) {expr.etype |= XPR_ERROR; expr.value.u = ERR_WRONG_TYPE;} |
expr.instruction = II_SHIFT_LEFT; break; |
case '>' + D2: // >> |
if (swapped) {expr.etype |= XPR_ERROR; expr.value.u = ERR_WRONG_TYPE;} |
expr.instruction = II_SHIFT_RIGHT_S; break; |
case '>' + D3: // >>> |
if (swapped) {expr.etype |= XPR_ERROR; expr.value.u = ERR_WRONG_TYPE;} |
expr.instruction = II_SHIFT_RIGHT_U; break; |
default: |
expr.etype |= XPR_ERROR; expr.value.u = ERR_WRONG_TYPE; |
} |
return expr; |
} |
|
|
// Interpret dyadic expression generating memory operand. |
// both expressions are inside [] or at least one contains components other than integer constants |
SExpression CAssembler::op2Memory(uint32_t op, SExpression & exp1, SExpression & exp2) { |
SExpression expr; // return value |
SExpression expt; // temporary value |
expr.tokens = exp1.tokens + exp2.tokens + 1; // total number of tokens |
uint64_t f; // temporary factor |
int32_t symi1 = 0, symi2 = 0; // symbol indexes |
|
if (!((exp1.etype|exp2.etype) & (XPR_IMMEDIATE|XPR_BASE|XPR_INDEX|XPR_OPTION|XPR_SYM1|XPR_SYM2|XPR_LIMIT|XPR_LENGTH|XPR_BROADC))) { |
// combination of only integer expressions inside [] |
// combine everything from the two operands |
expr = exp1 | exp2; |
expr.tokens = exp1.tokens + exp2.tokens + 1; |
expr.etype &= ~XPR_OP; expr.instruction = 0; // operator is resolved here |
switch (op) { |
case '+': // adding offsets |
expr.offset_mem = exp1.offset_mem + exp2.offset_mem; |
break; |
case '-': // |
expr.offset_mem = exp1.offset_mem - exp2.offset_mem; |
break; |
case '*': |
expr.offset_mem = exp1.offset_mem * exp2.offset_mem; |
break; |
case '/': |
if (exp2.offset_mem == 0) { |
expr.etype |= XPR_ERROR; |
expr.value.u = ERR_OVERFLOW; |
break; |
} |
expr.offset_mem = exp1.offset_mem / exp2.offset_mem; |
break; |
case '<' + D2: // << |
expr.offset_mem = exp1.offset_mem << exp2.offset_mem; |
break; |
case '>' + D2: // >> shift right signed |
expr.offset_mem = exp1.offset_mem >> exp2.offset_mem; // signed shift right |
break; |
case '>' + D3: // >>> unsigned shift right |
expr.offset_mem = uint32_t(exp1.offset_mem) >> uint32_t(exp2.offset_mem); // unsigned shift right |
break; |
default: // wrong operator |
expr.value.u = ERR_WRONG_TYPE; |
expr.etype |= XPR_ERROR; return expr; |
} |
return expr; |
} |
|
// not only integer expressions |
if ((exp2.etype & XPR_SYM1) && op == '-') { |
// subtracting two symbol addresses |
if (exp1.sym1) { |
exp2.sym2 = exp2.sym1; exp2.sym1 = 0; |
exp2.etype = (exp2.etype & ~XPR_SYM1) | XPR_SYM2; |
if (exp1.symscale1 == 0) exp1.symscale1 = 1; |
if (exp2.symscale1 == 0) exp2.symscale1 = 1; |
if (exp1.symscale1 != exp2.symscale1 || exp2.sym2 == 0) { |
exp1.value.u = ERR_CONFLICT_TYPE; // conflicting scale factors |
exp1.etype |= XPR_ERROR; return exp1; |
} |
} |
else if (exp1.sym3) { |
exp2.sym4 = exp2.sym3; exp2.sym3 = 0; |
exp2.etype = (exp2.etype & ~XPR_SYM1) | XPR_SYM2; |
if (exp1.symscale3 == 0) exp1.symscale3 = 1; |
if (exp2.symscale3 == 0) exp2.symscale3 = 1; |
if (exp1.symscale3 != exp2.symscale3 || exp2.sym4 == 0) { |
exp1.value.u = ERR_CONFLICT_TYPE; // conflicting scale factors |
exp1.etype |= XPR_ERROR; return exp1; |
} |
} |
else { |
exp1.value.u = ERR_CONFLICT_TYPE; // conflicting scale factors |
exp1.etype |= XPR_ERROR; return exp1; |
} |
} |
// error checks |
if (exp1.etype & exp2.etype & (XPR_SYM1 | XPR_SYM2 | XPR_SYMSCALE | XPR_INDEX |
| XPR_LIMIT | XPR_LENGTH | XPR_BROADC)) { |
exp1.value.u = ERR_MEM_COMPONENT_TWICE; // some component or option specified twice |
exp1.etype |= XPR_ERROR; return exp1; |
} |
if (((exp1.etype | exp2.etype) & (XPR_LIMIT | XPR_OFFSET)) == (XPR_LIMIT | XPR_OFFSET)) { |
exp1.value.u = ERR_LIMIT_AND_OFFSET; // cannot have both offset and limit |
exp1.etype |= XPR_ERROR; return exp1; |
} |
|
if ((exp2.etype & XPR_BASE) && ((exp1.etype & XPR_BASE) || op == '-')) { |
// adding two registers or subtracting a register. make the second an index register |
if (exp2.base == 31 && (exp1.etype & XPR_BASE) && !(exp2.etype & XPR_INDEX)) { |
// stack pointer cannot be index. make first register an index instead |
exp1.index = exp1.base; exp1.base = 0; |
exp1.etype = (exp1.etype & ~XPR_BASE) | XPR_INDEX; |
exp1.scale = 1; |
} |
else { |
exp2.index = exp2.base; exp2.base = 0; |
exp2.etype = (exp2.etype & ~XPR_BASE) | XPR_INDEX; |
exp2.scale = 1; |
} |
} |
// combine everything from the two operands |
expr = exp1 | exp2; |
expr.tokens = exp1.tokens + exp2.tokens + 1; |
expr.value.u = exp1.value.u + exp2.value.u; // add values, except for special cases below |
expr.offset_mem = exp1.offset_mem + exp2.offset_mem; // add offsets, except for special cases below |
expr.offset_jump = exp1.offset_jump + exp2.offset_jump; // add jump offsets |
expr.etype &= ~XPR_OP; expr.instruction = 0; // operator is resolved here |
|
switch (op) { |
case '+': // adding components. offsets have been added above |
/* Changed: immediate value outside [] cannot be converted to offset: |
if ((expr.etype & (XPR_REG | XPR_BASE | XPR_SYM1)) && (expr.etype & XPR_INT) && (expr.etype & XPR_MEM)) { |
// adding offset. convert value to offset |
expr.offset += expr.value.i; |
expr.value.i = 0; |
expr.etype = (expr.etype | XPR_OFFSET) & ~XPR_IMMEDIATE; |
} */ |
break; |
case ',': // combining components. components are combined below |
if (exp1.value.u && exp2.value.u) { |
expr.value.u = ERR_WRONG_TYPE; // cannot combine integer offsets with comma operator |
expr.etype |= XPR_ERROR; return expr; |
} |
if ((expr.etype & XPR_INDEX) && (expr.etype & (XPR_LENGTH | XPR_BROADC))) { // both index and broadcast |
if (expr.scale == -1) { |
if (expr.index != expr.length) { // scale = -1. index and length must be the same |
expr.value.u = ERR_NEG_INDEX_LENGTH; |
expr.etype |= XPR_ERROR; return expr; |
} |
} |
else { // cannot have index and length/broadcast |
expr.value.u = ERR_INDEX_AND_LENGTH; |
expr.etype |= XPR_ERROR; return expr; |
} |
} |
break; |
case '-': // subtract offsets or registers (symbol addresses subtracted above) |
/* Changed: immediate value outside [] cannot be converted to offset: |
if ((exp1.etype & (XPR_REG | XPR_BASE | XPR_SYM1)) && (exp2.etype & XPR_INT) && (expr.etype & XPR_MEM)) { |
// subtracting offset. convert value to offset |
expr.offset = exp1.offset - exp2.value.i; |
expr.value.i = 0; |
expr.etype = (expr.etype | XPR_OFFSET) & ~XPR_IMMEDIATE; |
} |
else */ |
{ |
expr.offset_mem = exp1.offset_mem - exp2.offset_mem; |
expr.offset_jump = exp1.offset_jump - exp2.offset_jump; |
expr.value.u = exp1.value.u - exp2.value.u; |
} |
if (exp2.etype & XPR_INDEX) { // subtracting a register gives negative index |
expr.scale = - exp2.scale; |
} |
else if ((exp1.etype & XPR_SYM1) && (exp2.etype & XPR_SYM2)) { |
// subtracting two symbols. has been fixed above |
// check if symbols are in the same domain |
if (exp1.sym1) { |
symi1 = findSymbol(exp1.sym1); |
symi2 = findSymbol(exp2.sym2); |
} |
else if (exp1.sym3) { |
symi1 = findSymbol(exp1.sym3); |
symi2 = findSymbol(exp2.sym4); |
} |
if (symi1 > 0 && symi2 > 0 |
&& (symbols[symi1].st_other & symbols[symi2].st_other & (SHF_IP | SHF_DATAP | SHF_THREADP)) == 0 |
&& (symbols[symi1].st_type & symbols[symi2].st_type & STT_CONSTANT) == 0) { |
errors.reportLine(ERR_RELOCATION_DOMAIN); |
} |
} |
//else if ((expr.etype & XPR_IMMEDIATE) == XPR_INT) expr.etype |= XPR_OFFSET; // value is offset |
if (exp2.etype & (XPR_SYM1|XPR_SYMSCALE)) { |
expr.value.u = ERR_WRONG_TYPE; // cannot subtract these components |
expr.etype |= XPR_ERROR; return expr; |
} |
break; |
case '<'+D2: // index << s = index * (1 << s) |
//exp2.value.u = (uint64_t)1 << exp2.value.u; |
exp2.offset_mem = 1 << exp2.offset_mem; |
goto MULTIPLYINDEX; // continue in case '*' |
case '*': // indexregister * scale |
if ((exp1.etype & (XPR_INT|XPR_OFFSET)) && (exp2.etype & (XPR_BASE|XPR_INDEX))){ |
// first operand is integer, second operand is register. swap operands |
expt = exp2; exp2 = exp1; exp1 = expt; |
} |
MULTIPLYINDEX: |
if ((exp1.etype & XPR_BASE) && !(exp1.etype & XPR_INDEX)) { // convert base to index |
exp1.index = exp1.base; exp1.base = 0; exp1.scale = 1; |
exp1.etype = (exp1.etype & ~XPR_BASE) | XPR_INDEX; |
} |
if (exp2.etype & XPR_INT) { // convert integer to offset. should not occur |
exp2.offset_mem = exp2.value.w; exp2.value.i = 0; |
exp2.etype = (exp2.etype & ~XPR_INT) | XPR_OFFSET; |
} |
if (!(exp1.etype & XPR_INDEX) || !(exp2.etype & XPR_OFFSET) |
|| ((exp1.etype | exp2.etype) & (XPR_OPTION|XPR_SYM1|XPR_SYM2|XPR_LIMIT|XPR_LENGTH|XPR_BROADC))) { |
expr.value.u = ERR_WRONG_TYPE; // cannot multiply anything else |
expr.etype |= XPR_ERROR; return expr; |
} |
f = int64_t(exp2.offset_mem) * exp1.scale; |
if ((f & (f - 1)) || f == 0 || f > 16) { // check that scale is a power of 2, not bigger than 16 |
expr.value.u = ERR_SCALE_FACTOR; // wrong scale factor |
expr.etype |= XPR_ERROR; return expr; |
} |
expr.base = exp1.base; expr.index = exp1.index; |
expr.scale = (int8_t)f; |
expr.etype = exp1.etype | (exp2.etype & ~(XPR_INT|XPR_OFFSET)); |
expr.value.u = 0; |
expr.offset_mem = exp1.offset_mem; |
break; |
case '>'+D2: // divide (sym1-sym2) >> s = (sym1-sym2) / (1 << s) |
exp2.value.u = (uint64_t)1 << exp2.value.u; |
exp2.offset_mem = (uint64_t)1 << exp2.offset_mem; |
// continue in case '/' |
case '/': // divide (sym1-sym2) / scale |
if ((exp2.etype & XPR_OFFSET) && !(exp2.etype & (XPR_REG | XPR_INT | XPR_BASE))) { |
// constant has been interpreted as offset because it is inside []. change it to XPR_INT |
exp2.value.i = exp2.offset_mem; exp2.offset_mem = 0; |
exp2.etype = (exp2.etype & ~(XPR_OFFSET)) | XPR_INT; |
expr.offset_mem = exp1.offset_mem; |
} |
if (!(exp1.etype & XPR_SYM1) || ((exp2.etype & 0xF) != XPR_INT) |
|| ((exp1.etype | exp2.etype) & (XPR_REG|XPR_OPTION|XPR_LIMIT|XPR_LENGTH|XPR_BROADC))) { |
expr.value.u = ERR_WRONG_TYPE; // cannot divide anything else |
expr.etype |= XPR_ERROR; return expr; |
} |
f = exp2.value.u; |
if (exp1.symscale1) f *= exp1.symscale1; |
if ((f & (f - 1)) || f == 0 || f > 16) { // check that scale is a power of 2, not bigger than 16 |
expr.value.u = ERR_SCALE_FACTOR; // wrong scale factor |
expr.etype |= XPR_ERROR; return expr; |
} |
expr.symscale1 = (int8_t)f; |
expr.etype |= XPR_SYMSCALE; |
expr.etype = exp1.etype | (exp2.etype & ~XPR_INT); |
expr.value.u = exp1.value.u; |
break; |
case '=': // option = value |
// check if operands contain anything else |
if (!(exp1.etype & XPR_OPTION) || !(exp2.etype & (XPR_INT | XPR_BASE | XPR_REG)) |
|| ((exp1.etype | exp2.etype) & (XPR_SYM1|XPR_SYM2|XPR_REG2|XPR_INDEX|XPR_LIMIT|XPR_LENGTH|XPR_BROADC))) { |
expr.value.u = ERR_WRONG_TYPE; // cannot uses '=' on anyting else inside [] |
expr.etype |= XPR_ERROR; return expr; |
} |
switch (exp1.value.w) { |
case OPT_LENGTH: // length = register |
if ((exp2.etype & XPR_REG1) && (exp2.reg1 & REG_R)) { |
// length = register, outside [] |
expr.etype = XPR_LENGTH | XPR_MEM; |
expr.length = exp2.reg1; |
expr.base = 0; |
expr.value.i = 0; |
break; |
} |
// length = register, inside [] |
if (!(exp2.etype & XPR_BASE) || (exp2.base & 0xE0) != REG_R) { |
expr.value.u = ERR_WRONG_TYPE; // cannot uses '=' on anyting else inside [] |
expr.etype |= XPR_ERROR; return expr; |
} |
expr.etype = XPR_LENGTH | XPR_MEM; |
expr.length = exp2.base; |
expr.base = 0; |
expr.value.i = 0; |
break; |
case OPT_BROADCAST: // broadcast = register |
if (!(exp2.etype & XPR_BASE) || (exp2.base & 0xE0) != REG_R) { |
expr.value.u = ERR_WRONG_TYPE; // cannot uses '=' on anyting else inside [] |
expr.etype |= XPR_ERROR; return expr; |
} |
expr.etype = XPR_BROADC | XPR_MEM; |
expr.length = exp2.base; |
expr.base = 0; |
expr.value.i = 0; |
break; |
case OPT_LIMIT: // limit = integer |
if (!(exp2.etype & XPR_INT)) { |
expr.value.u = ERR_WRONG_TYPE; // cannot uses '=' on anyting else inside [] |
expr.etype |= XPR_ERROR; return expr; |
} |
if (exp1.etype & XPR_OFFSET) { // cannot have both limit and offset |
expr.etype = ERR_LIMIT_AND_OFFSET; |
expr.etype |= XPR_ERROR; return expr; |
} |
expr.etype = XPR_LIMIT | XPR_MEM; |
expr.value.u = exp2.value.u; |
break; |
case OPT_SCALAR: // scalar |
expr.etype = XPR_SCALAR | XPR_MEM; |
expr.value.i = 0; |
break; |
case OPT_MASK: |
if (!(exp2.etype & (XPR_REG | XPR_REG1))) { |
expr.etype = ERR_MASK_NOT_REGISTER; |
expr.etype |= XPR_ERROR; return expr; |
} |
expr.etype = XPR_MASK; |
expr.mask = exp2.reg1; |
expr.reg1 = 0; |
break; |
case OPT_FALLBACK: |
if (exp2.etype == (XPR_REG | XPR_REG1) && (exp2.reg1 & 0x1F) != 0x1F) { |
expr.fallback = exp2.reg1; |
expr.etype = XPR_FALLBACK; |
expr.reg1 = 0; |
} |
else if ((exp2.etype & XPR_IMMEDIATE) && exp2.value.i == 0){ |
expr.fallback = (expr.mask & 0xF0) | 0x1F; |
expr.etype = XPR_FALLBACK; |
} |
else { |
expr.value.u = ERR_FALLBACK_WRONG; |
expr.etype |= XPR_ERROR; return expr; |
} |
break; |
case OPT_OPTIONS: |
if ((exp2.etype & 0xF) == XPR_INT) { |
expr.etype = (expr.etype & ~XPR_IMMEDIATE) | XPR_OPTIONS; |
expr.optionbits = (uint8_t)exp2.value.u; // move value to optionbits |
expr.value.i = 0; |
return expr; |
} |
else { |
expr.etype = ERR_WRONG_TYPE; |
expr.etype |= XPR_ERROR; |
return expr; |
} |
break; |
default: // mask and fallback options not allowed inside [] |
expr.value.u = ERR_NOT_INSIDE_MEM; // change error message |
expr.etype |= XPR_ERROR; return expr; |
} |
break; |
|
default: // wrong operator |
expr.value.u = ERR_WRONG_TYPE; |
expr.etype |= XPR_ERROR; return expr; |
} |
if ((expr.etype & XPR_INT) && !(expr.etype & (XPR_SYM1 | XPR_INDEX))) { // value not used otherwise is offset |
expr.etype = (expr.etype & ~(XPR_INT)) | XPR_OFFSET; |
} |
return expr; |
} |
|
|
// Interpreted triadic expression exp1 ? exp2 : exp3 at the indicated positions |
SExpression CAssembler::op3(uint32_t tok1, uint32_t toklow, uint32_t tokcolon, uint32_t maxtok, uint32_t options) { |
SExpression exp1, exp2; |
uint32_t cond; // evaluated condition |
|
exp1 = expression(tok1, toklow - tok1, options); // evaluate expression before '?' |
if (exp1.tokens != toklow - tok1) errors.report(tokens[tok1 + exp1.tokens]); |
|
if ((exp1.etype & XPR_REG) == 0 && (exp1.etype & (XPR_INT | XPR_FLT | XPR_STRING))) { |
// condition is a constant. just choose one of the two operands |
|
if ((exp1.etype & 0xF) == XPR_FLT) cond = exp1.value.d != 0.; // evaluate condition to true or false |
else if ((exp1.etype & 0xF) == XPR_STRING) { // string is false if empty or "0" |
cond = (exp1.sym2 != 0 && (exp1.sym2 > 1 || stringBuffer.get<uint16_t>((uint32_t)exp1.value.u) != '0')); |
} |
else cond = exp1.value.i != 0; |
|
// the expression that is not selected is evaluated with option = 0x10 to suppress errors but still count the tokens |
exp1 = expression(toklow + 1, tokcolon - (toklow + 1), options | (cond ^ 1) << 4); // evaluate first expression |
if (exp1.tokens != tokcolon - (toklow + 1)) errors.report(tokens[toklow + 1 + exp1.tokens]); |
exp2 = expression(tokcolon + 1, tok1 + maxtok - (tokcolon + 1), options | cond << 4); // evaluate second expression |
|
// number of tokens |
exp1.tokens = exp2.tokens = tokcolon - tok1 + 1 + exp2.tokens; |
|
// return the chosen expression |
if (cond) return exp1; else return exp2; |
} |
|
// condition is not a constant. It must be a mask register |
if ((exp1.etype & XPR_REG) == 0 || exp1.reg1 == 0 || exp1.etype & (XPR_OP|XPR_OPTION|XPR_MEM|XPR_SYM1|XPR_MASK|XPR_UNRESOLV)) { |
errors.report(tokens[tok1].pos, tokens[tok1].stringLength, ERR_MASK_NOT_REGISTER); |
} |
uint8_t maskreg = exp1.reg1; // save mask register |
|
// evaluate the middle expression |
exp1 = expression(toklow + 1, tokcolon - (toklow + 1), options); |
if (exp1.tokens != tokcolon - (toklow + 1)) errors.report(tokens[toklow + 1 + exp1.tokens]); |
|
// third expression must be fallback |
exp2 = expression(tokcolon + 1, tok1 + maxtok - (tokcolon + 1), options); |
uint8_t fallbackreg = 0; // fallback register |
if (exp2.etype & XPR_REG) { |
fallbackreg = exp2.reg1; |
exp1.etype |= XPR_FALLBACK; |
} |
else if ((exp2.etype & (XPR_INT | XPR_FLT)) && exp2.value.i == 0) { |
fallbackreg = maskreg | 0x1F; // register 31 with same type as mask register |
exp1.etype |= XPR_FALLBACK; |
} |
if (exp2.etype & (XPR_STRING | XPR_OP | XPR_OPTION | XPR_MEM | XPR_SYM1 | XPR_MASK) || exp2.value.i) { |
errors.report(tokens[tokcolon+1].pos, tokens[tokcolon+exp2.tokens+1].pos - tokens[tokcolon+1].pos, ERR_FALLBACK_WRONG); |
} |
// insert mask and fallback in exp1 |
exp1.etype |= XPR_MASK; |
exp1.mask = maskreg; |
exp1.fallback = fallbackreg; |
exp1.tokens = tokcolon - tok1 + 1 + exp2.tokens; |
return exp1; |
} |
|
|
// Convert -(expression), e.g. -(A-B) |
SExpression CAssembler::op1minus(SExpression & exp1) { |
exp1.tokens++; |
if ((exp1.etype & (XPR_REG | XPR_MEM)) && !(exp1.etype & XPR_OP) && exp1.value.i == 0) { // -reg or -mem |
exp1.etype |= XPR_OP | XPR_INT; |
exp1.instruction = II_SUB_REV; // 0 - expression |
} |
else if (exp1.instruction == II_SUB) exp1.instruction = II_SUB_REV; |
else if (exp1.instruction == II_SUB_REV) exp1.instruction = II_SUB; |
else if (exp1.instruction == II_ADD_ADD) exp1.optionbits ^= 3; |
else if (exp1.instruction == II_MUL_ADD || exp1.instruction == II_MUL_ADD2) exp1.optionbits ^= 0xF; |
else if (exp1.instruction == II_ADD && !(exp1.etype & (XPR_IMMEDIATE | XPR_MEM | XPR_SYM1))) { |
// -(R1+R2) = -R1 -R2 + 0 |
exp1.instruction = II_ADD_ADD; |
exp1.value.i = 0; |
exp1.optionbits = 3; |
exp1.etype |= XPR_INT; |
} |
else if (exp1.instruction == II_ADD && (exp1.etype & XPR_IMMEDIATE)) { |
// -(R1+I) = -R1 + (-I) |
exp1.instruction = II_SUB_REV; |
if ((exp1.etype & XPR_IMMEDIATE) == XPR_FLT) exp1.value.d = -exp1.value.d; |
else exp1.value.i = -exp1.value.i; |
} |
else if ((exp1.instruction == 0 || exp1.instruction == II_MUL || exp1.instruction == II_DIV || exp1.instruction == II_DIV_REV) |
&& (exp1.etype & XPR_IMMEDIATE)) { |
// -I or -(A*I) |
if (exp1.etype & XPR_FLT) exp1.value.d = -exp1.value.d; |
else exp1.value.i = -exp1.value.i; |
} |
else if (exp1.instruction == II_MUL && !(exp1.etype & XPR_IMMEDIATE)) { |
exp1.instruction = II_MUL_ADD; |
exp1.optionbits ^= 3; |
exp1.etype |= XPR_INT; |
} |
else { |
exp1.etype = XPR_ERROR; |
exp1.value.u = ERR_TOO_COMPLEX; // cannot apply '-' to other expressions |
} |
return exp1; |
} |
|
// Interpret dyadic expression with string operands |
SExpression CAssembler::op2String(uint32_t op, SExpression const & exp1, SExpression const & exp2) { |
if (op != '+') { |
SExpression exp3; |
exp3.etype = XPR_ERROR; |
exp3.value.u = ERR_WRONG_TYPE; |
return exp3; |
} |
// operation is +. concatenate strings, convert numeric to string |
|
uint32_t stringpos1 = stringBuffer.dataSize(); // current position in string buffer |
uint32_t stringpos2; // position of second part of concatenated string |
const int maxIntLength = 32; // maximum length of integer as string |
const int maxFloatLength = 48; |
const char * wrongType = "-wrong type!-"; |
uint32_t len = 0; // length of string |
|
// first operand |
if (exp1.etype == XPR_STRING) { |
stringBuffer.push(stringBuffer.buf() + exp1.value.u, exp1.sym2); // copy to string buffer without terminating zero |
stringBuffer.put((char)0); |
//stringpos2 = stringBuffer.dataSize(); |
} |
else if (exp1.etype == XPR_INT) { // convert integer to string |
stringBuffer.push(&exp1, maxIntLength); // put in anyting here to make space for writing string |
if (sizeof(long int) >= 8) { |
#ifndef _WIN32 // suppress warning |
sprintf((char*)stringBuffer.buf()+stringpos1, "%li", exp1.value.i); |
#endif |
} |
else { |
sprintf((char*)stringBuffer.buf()+stringpos1, "%lli", (long long)exp1.value.i); |
} |
} |
else if (exp1.etype == XPR_FLT) { // convert float to string |
stringBuffer.push(&exp1, maxFloatLength); // put in anyting here to make space for writing string |
sprintf((char*)stringBuffer.buf()+stringpos1, "%g", exp1.value.d); |
} |
else { |
stringBuffer.put(wrongType); |
} |
len = (uint32_t)strlen((char*)stringBuffer.buf()+stringpos1); |
stringpos2 = stringpos1 + len; |
stringBuffer.setSize(stringpos2); // remove extra space |
|
// second operand |
if (exp2.etype == XPR_STRING) { |
stringBuffer.push(stringBuffer.buf() + exp2.value.u, exp2.sym2); // copy to string buffer without terminating zero |
stringBuffer.put((char)0); |
} |
else if (exp2.etype == XPR_INT) { // convert integer to string |
stringBuffer.push(&exp2, maxIntLength); // put in anyting here to make space for writing string |
if (sizeof(long int) >= 8) { |
#ifndef _WIN32 // suppress warning |
sprintf((char*)stringBuffer.buf()+stringpos2, "%li", exp2.value.i); |
#endif |
} |
else { |
sprintf((char*)stringBuffer.buf()+stringpos2, "%lli", (long long)exp2.value.i); |
} |
len = (uint32_t)strlen((char*)stringBuffer.buf()+stringpos2); |
stringBuffer.setSize(stringpos2 + len + 1); |
} |
else if (exp2.etype == XPR_FLT) { // convert float to string |
stringBuffer.push(&exp2, maxFloatLength); // put in anyting here to make space for writing string |
sprintf((char*)stringBuffer.buf()+stringpos2, "%g", exp2.value.d); |
len = (uint32_t)strlen((char*)stringBuffer.buf()+stringpos2); |
stringBuffer.setSize(stringpos2 + len + 1); |
} |
else { |
stringBuffer.put(wrongType); |
} |
SExpression exp3; |
exp3.etype = XPR_STRING; |
exp3.value.u = stringpos1; |
exp3.sym2 = (uint32_t)strlen((char*)stringBuffer.buf() + stringpos1); |
exp3.tokens = exp1.tokens + exp2.tokens + 1; |
return exp3; |
} |
|
|
double interpretFloat(const char * s, uint32_t length) { |
// interpret floating point number from string with indicated length |
char buffer[64]; |
if (length >= sizeof(buffer)) { |
union { |
uint64_t i; |
double d; |
} nan = {0xFFFFC00000000000}; |
return nan.d; // return NAN |
} |
memcpy(buffer, s, length); |
buffer[length] = 0; // terminate string |
double r; |
sscanf(buffer, "%lf", &r); // convert string to double |
return r; |
} |
|
// make expression out of symbol |
SExpression CAssembler::symbol2expression(uint32_t symi) { |
SExpression expr; |
zeroAllMembers(expr); |
|
switch (symbols[symi].st_type) { |
case STT_CONSTANT: case STT_VARIABLE: |
expr.etype = XPR_INT; // default type |
expr.sym1 = symi; |
if (symbols[symi].st_other & STV_FLOAT) expr.etype = XPR_FLT; |
if (symbols[symi].st_other & STV_STRING) { |
expr.etype = XPR_STRING; |
expr.sym2 = (uint32_t)symbols[symi].st_unitnum; |
} |
expr.value.u = symbols[symi].st_value; |
break; |
case STT_EXPRESSION: |
if (symbols[symi].st_value < expressions.numEntries()) { |
expr = expressions[uint32_t(symbols[symi].st_value)]; |
} |
else { |
expr.etype = XPR_ERROR; |
expr.value.u = TOK_XPR; |
} |
break; |
default: |
expr.etype = XPR_ERROR; |
expr.value.u = ERR_CONFLICT_TYPE; |
} |
expr.tokens = 0; |
return expr; |
} |