OpenCores
URL https://opencores.org/ocsvn/forwardcom/forwardcom/trunk

Subversion Repositories forwardcom

[/] [forwardcom/] [bintools/] [assem3.cpp] - Rev 77

Go to most recent revision | Compare with Previous | Blame | View Log

/****************************    assem3.cpp    ********************************
* Author:        Agner Fog
* Date created:  2017-04-17
* Last modified: 2020-05-17
* Version:       1.10
* Project:       Binary tools for ForwardCom instruction set
* Module:        assem.cpp
* Description:
* Module for assembling ForwardCom .as files. 
* This module contains:
* Assemble-time variable assignments and metaprogramming features,
* Copyright 2017-2020 GNU General Public License http://www.gnu.org/licenses
******************************************************************************/
#include "stdafx.h"
 
// Replace meta variables defined in previous '%' line
void CAssembler::replaceKnownNames() {
    // loop through tokens, replace known symbol names by reference to symbol records
    // and replace assemble-time variables by their current value
    uint32_t tok;                                // token index
    int32_t symi;                                // symbol index
    for (tok = tokenB; tok < tokenB + tokenN; tok++) {
        if (lineError) break; 
        if (tokens[tok].type == TOK_NAM) {
            // name found. search for it in symbol table
            symi = findSymbol((char*)buf() + tokens[tok].pos, tokens[tok].stringLength);
            if (symi > 0) {  // symbol found. replace token by reference to symbol                
                tokens[tok].id = symbols[symi].st_name;  // use name offset as unique identifier because symbol index can change
                if (symbols[symi].st_type == STT_EXPRESSION) {
                    tokens[tok].type = TOK_XPR;
                    // save value of meta variable in token in case it changes later
                    tokens[tok].value.u = symbols[symi].st_value;
                }
                else if (symbols[symi].st_type == STT_TYPENAME) {    // symbol is an alias for a type name
                    if (tokens[tokenB].id != '%' || tok != tokenB + 1) { // replace it unless it comes immediately after %, which means it is redefined
                        tokens[tok].type = TOK_TYP; 
                        tokens[tok].value.u = symbols[symi].st_value;
                        tokens[tok].id = (uint32_t)symbols[symi].st_value;
                    }
                }
                else {
                    tokens[tok].type = TOK_SYM;
                    if ((symbols[symi].st_type & ~1) == STT_CONSTANT) {
                        // save value of meta variable in token in case it changes later
                        tokens[tok].value.u = symbols[symi].st_value;
                        tokens[tok].vartype = 3;
                        if (symbols[symi].st_other & STV_FLOAT) {
                            tokens[tok].vartype = 5;
                        }
                    }
                }
            }
        } /*  not needed because meta code cannot have forward references, except in public directives which are handled elsewhere
        else if (tokens[tok].type == TOK_SYM) {
            symi = findSymbol(tokens[tok].value.w);
            if ((symbols[symi].st_type & ~1) == STT_CONSTANT) {
                // save value of meta variable in token in case it changes later
                tokens[tok].value.u = symbols[symi].st_value;
                tokens[tok].vartype = symbols[symi].st_reguse1;
            }
        } */
    }
}
 
 
// Interpret line beginning with '%' containing meta code
void CAssembler::interpretMetaDefinition() {
    uint32_t tok;                                // token index
    int32_t symi = 0;                            // symbol index
    ElfFWC_Sym2 sym;                             // symbol record
    zeroAllMembers(sym);                         // reset symbol
    //uint32_t tokmeta = 0;                        // token containing '%'
 
    // interpret line defining assemble-time variable
    uint32_t state = 0;   // state during definition of assemble-time variable:
                          // 1: after '%'
                          // 2: after type name
                          // 3: after variable name
                          // 4: after '=' or '+=', etc.
                          // 5: finished assignment
    uint32_t toktyp = 0;  // token containing type definition
    uint32_t tokop = 0;   // token containing ++ or -- operator
    uint32_t type = 3;    // default type is int64
    SExpression exps, expr;
    zeroAllMembers(expr);
 
    lineError = false;
    for (tok = tokenB; tok < tokenB + tokenN; tok++) {
        if (lineError)  break;
 
        if (state == 4) {
            // after assignment operator, expecting expression next
            expr = expression(tok, tokenB + tokenN - tok, 0);
            if (tok + expr.tokens < tokenB + tokenN) {
                errors.report(tokens[tok + expr.tokens]);  // extra tokens on line
            }
            exps = symbol2expression(symi); // make expression out of symbol
            if (lineError) break;
 
            // combine expressions
            switch (tokens[tok - 1].id) {
            case '=':  break;         // assign expr
            case '+' + EQ:            // +=
                expr = op2('+', exps, expr);  break;
            case '-' + EQ:            // -=
                expr = op2('-', exps, expr);  break;
            case '*' + EQ:            // *=
                expr = op2('*', exps, expr);  break;
            case '/' + EQ:            // /=
                expr = op2('/', exps, expr);  break;
            case '&' + EQ:            // &=
                expr = op2('&', exps, expr);  break;
            case '|' + EQ:            // |=
                expr = op2('|', exps, expr);  break;
            case '^' + EQ:            // ^=
                expr = op2('^', exps, expr);  break;
            case '<' + D2 + EQ:            // <<=
                expr = op2('<' + D2, exps, expr);  break;
            case '>' + D2 + EQ:            // >>=
                expr = op2('>' + D2, exps, expr);  break;
            case '>' + D3 + EQ:            // >>>=
                expr = op2('>' + D3, exps, expr);  break;
            default:
                errors.report(tokens[tok - 1].pos, tokens[tok - 1].stringLength, ERR_WRONG_TYPE);
            }
            if (expr.etype == uint32_t(XPR_ERROR)) {
                errors.report(tokens[tok - 1].pos, tokens[tok - 1].stringLength, expr.value.w);
            }
            else assignMetaVariable(symi, expr, toktyp);
            if (lineError) continue;
            state = 5;
            break;
        }
        if (state == 5) {
            errors.report(tokens[tok]);    // extra tokens on line
            return;
        }
        switch (tokens[tok].type) {
        case TOK_OPR:  // operator
            if (tokens[tok].id == '%' && state == 0) {
                state = 1;
            }
            else if (tokens[tok].priority == 15 && state == 3) state = 4; // assignment operator
            else if (tokens[tok].priority == 3) { // ++ or -- operator
                tokop = tok;
                if (state < 3) break;
                if (state == 3) {
                PLUSPLUSOPERATOR:
                    exps = symbol2expression(symi); // make expression out of symbol
                    expr.etype = XPR_INT;
                    expr.value.i = 1;
                    expr.tokens = 0;
                    switch (tokens[tokop].id) {
                    case '+' + D2:            // ++
                        expr = op2('+', exps, expr);  break;
                    case '-' + D2:            // --
                        expr = op2('-', exps, expr);  break;
                    default:
                        errors.report(tokens[tokop]);
                    }
                    if (expr.etype & XPR_ERROR) {
                        errors.report(tokens[tok - 1].pos, tokens[tok - 1].stringLength, expr.value.w);
                    }
                    else assignMetaVariable(symi, expr, toktyp);
                    lines[linei].type = LINE_METADEF;
                    state = 5;
                }
            }
            else tok = tokenB + tokenN;   // anything else. exit loop
            break;
        case TOK_TYP:  // type name
            toktyp = tok;  type = tokens[tok].vartype;
            if (state == 1) state = 2;
            break;
        case TOK_NAM:  // new name. define symbol
            if (state == 0) break;
            if (state >= 3) { errors.report(tokens[tok]);  break; }
            sym.st_name = symbolNameBuffer.putStringN((char*)buf() + tokens[tok].pos, tokens[tok].stringLength);
            symi = symbols.addUnique(sym);
            symbols[symi].st_type = 0;  // remember that symbol has no value yet
            symbols[symi].st_section = SECTION_LOCAL_VAR;  // remember symbol is not external. use arbitrary section
            symbols[symi].st_unitsize = 8;
            symbols[symi].st_unitnum = 1;
            tokens[tok].type = TOK_SYM;  // change token type
            tokens[tok].id = symbols[symi].st_name;
            tokens[tok].vartype = type;
            //if (state == 8) goto PLUSPLUSOPERATOR;
            state = 3;
            break;
        case TOK_SYM: case TOK_XPR: // existing symbol found
            if (state != 1 && state != 2) break;
            symi = findSymbol(tokens[tok].id);
            if (symi < 1) errors.report(tokens[tok]);    // unknown error
            if ((symbols[symi].st_type & ~1) == STT_CONSTANT) {
                symbols[symi].st_type = STT_VARIABLE;  // remember symbol has been modified
                if (tokop && tokop == tok - 1 && state < 3) goto PLUSPLUSOPERATOR;
            }
            state = 3;
            break;
        default:  // anything else. exit loop
            tok = tokenB + tokenN;
        }
    }
    // insert metaprogramming branches, loops and functions here??
}
 
 
// define or modify assemble-time constant or variable
void CAssembler::assignMetaVariable(uint32_t symi, SExpression & expr, uint32_t typetoken) {
    // get value and type from expression 
 
    symbols[symi].st_value = expr.value.u;
    uint32_t type = XPR_INT;
    // set variable type
    switch (expr.etype & 0xF) {
    case XPR_FLT:
        symbols[symi].st_other = STV_FLOAT;
        type = XPR_FLT;
        break;
    case XPR_STRING:
        symbols[symi].st_other = STV_STRING;
        symbols[symi].st_unitsize = 1;
        symbols[symi].st_unitnum = expr.sym2;    // string length
        type = XPR_STRING;
        break;
    default: 
        symbols[symi].st_other = 0;
    }
    if (expr.etype & XPR_TYPENAME) symbols[symi].st_type = STT_TYPENAME;
    else if (symbols[symi].st_type == 0) symbols[symi].st_type = STT_CONSTANT;  // first time: make a constant
    else symbols[symi].st_type = STT_VARIABLE;                             // reassigned later: make a variable
    if (expr.etype & (XPR_REG | XPR_MEM)) {
        symbols[symi].st_type = STT_EXPRESSION;
        symbols[symi].st_value = expressions.push(expr);                         // save expression
    }
 
    // check expression type
    if (expr.etype & (XPR_OP | XPR_OPTION | XPR_SYMSCALE | XPR_MASK)) {
        errors.reportLine(ERR_WRONG_TYPE_VAR);
        return;
    }
    if ((expr.etype & (XPR_SYM1 | XPR_SYM2)) == XPR_SYM1 && !(expr.etype & XPR_MEM)) {
        // single symbol. must be constant or memory
        int32_t symi1 = findSymbol(expr.sym1);
        if (symi1 <= 0 || (!(symbols[symi1].st_type & STT_CONSTANT))) {
            errors.reportLine(ERR_WRONG_TYPE_VAR);
            return;
        }
    }
    // check if type matches
    if (typetoken == 0 || type == (tokens[typetoken].id & 0xF)) return;       // type matches
    if ((tokens[typetoken].id & 0xF) == XPR_FLT && type == XPR_INT) {
        // convert int to double
        expr.value.d = (double)expr.value.i;
        symbols[symi].st_value = expr.value.u;
        symbols[symi].st_other = STV_FLOAT;
        return;
    }
 
    errors.reportLine(ERR_WRONG_TYPE_VAR);
}
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.