⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 intcode.cpp

📁 plc软件的源代码 支持PIC ATMEGA单片机
💻 CPP
📖 第 1 页 / 共 3 页
字号:
//-----------------------------------------------------------------------------
// Copyright 2007 Jonathan Westhues
//
// This file is part of LDmicro.
// 
// LDmicro is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// LDmicro is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with LDmicro.  If not, see <http://www.gnu.org/licenses/>.
//------
//
// Generate intermediate code for the ladder logic. Basically generate code
// for a `virtual machine' with operations chosen to be easy to compile to
// AVR or PIC16 code.
// Jonathan Westhues, Nov 2004
//-----------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
#include <setjmp.h>
#include <stdlib.h>

#include "ldmicro.h"
#include "intcode.h"

IntOp IntCode[MAX_INT_OPS];
int IntCodeLen;

static DWORD GenSymCountParThis;
static DWORD GenSymCountParOut;
static DWORD GenSymCountOneShot;
static DWORD GenSymCountFormattedString;

static WORD EepromAddrFree;

//-----------------------------------------------------------------------------
// Pretty-print the intermediate code to a file, for debugging purposes.
//-----------------------------------------------------------------------------
void IntDumpListing(char *outFile)
{
    FILE *f = fopen(outFile, "w");
    if(!f) {
        Error("Couldn't dump intermediate code to '%s'.", outFile);
    }

    int i;
    int indent = 0;
    for(i = 0; i < IntCodeLen; i++) {

        if(IntCode[i].op == INT_END_IF) indent--;
        if(IntCode[i].op == INT_ELSE) indent--;
    
        fprintf(f, "%3d:", i);
        int j;
        for(j = 0; j < indent; j++) fprintf(f, "    ");

        switch(IntCode[i].op) {
            case INT_SET_BIT:
                fprintf(f, "set bit '%s'", IntCode[i].name1);
                break;

            case INT_CLEAR_BIT:
                fprintf(f, "clear bit '%s'", IntCode[i].name1);
                break;

            case INT_COPY_BIT_TO_BIT:
                fprintf(f, "let bit '%s' := '%s'", IntCode[i].name1,
                    IntCode[i].name2);
                break;

            case INT_SET_VARIABLE_TO_LITERAL:
                fprintf(f, "let var '%s' := %d", IntCode[i].name1,
                    IntCode[i].literal);
                break;

            case INT_SET_VARIABLE_TO_VARIABLE:
                fprintf(f, "let var '%s' := '%s'", IntCode[i].name1,
                    IntCode[i].name2);
                break;

            case INT_SET_VARIABLE_ADD:
                fprintf(f, "let var '%s' := '%s' + '%s'", IntCode[i].name1,
                    IntCode[i].name2, IntCode[i].name3);
                break;

            case INT_SET_VARIABLE_SUBTRACT:
                fprintf(f, "let var '%s' := '%s' - '%s'", IntCode[i].name1,
                    IntCode[i].name2, IntCode[i].name3);
                break;

            case INT_SET_VARIABLE_MULTIPLY:
                fprintf(f, "let var '%s' := '%s' * '%s'", IntCode[i].name1,
                    IntCode[i].name2, IntCode[i].name3);
                break;

            case INT_SET_VARIABLE_DIVIDE:
                fprintf(f, "let var '%s' := '%s' / '%s'", IntCode[i].name1,
                    IntCode[i].name2, IntCode[i].name3);
                break;

            case INT_INCREMENT_VARIABLE:
                fprintf(f, "increment '%s'", IntCode[i].name1);
                break;

            case INT_READ_ADC:
                fprintf(f, "read adc '%s'", IntCode[i].name1);
                break;

            case INT_SET_PWM:
                fprintf(f, "set pwm '%s' %s Hz", IntCode[i].name1,
                    IntCode[i].name2);
                break;

            case INT_EEPROM_BUSY_CHECK:
                fprintf(f, "set bit '%s' if EEPROM busy", IntCode[i].name1);
                break;
            
            case INT_EEPROM_READ:
                fprintf(f, "read EEPROM[%d,%d+1] into '%s'",
                    IntCode[i].literal, IntCode[i].literal, IntCode[i].name1);
                break;

            case INT_EEPROM_WRITE:
                fprintf(f, "write '%s' into EEPROM[%d,%d+1]",
                    IntCode[i].name1, IntCode[i].literal, IntCode[i].literal);
                break;

            case INT_UART_SEND:
                fprintf(f, "uart send from '%s', done? into '%s'",
                    IntCode[i].name1, IntCode[i].name2);
                break;

            case INT_UART_RECV:
                fprintf(f, "uart recv int '%s', have? into '%s'", 
                    IntCode[i].name1, IntCode[i].name2);
                break;

            case INT_IF_BIT_SET:
                fprintf(f, "if '%s' {", IntCode[i].name1); indent++;
                break;

            case INT_IF_BIT_CLEAR:
                fprintf(f, "if not '%s' {", IntCode[i].name1); indent++;
                break;

            case INT_IF_VARIABLE_LES_LITERAL:
                fprintf(f, "if '%s' < %d {", IntCode[i].name1,
                    IntCode[i].literal); indent++;
                break;

            case INT_IF_VARIABLE_EQUALS_VARIABLE:
                fprintf(f, "if '%s' == '%s' {", IntCode[i].name1,
                    IntCode[i].name2); indent++;
                break;

            case INT_IF_VARIABLE_GRT_VARIABLE:
                fprintf(f, "if '%s' > '%s' {", IntCode[i].name1,
                    IntCode[i].name2); indent++;
                break;

            case INT_END_IF:
                fprintf(f, "}");
                break;

            case INT_ELSE:
                fprintf(f, "} else {"); indent++;
                break;

            case INT_SIMULATE_NODE_STATE:
                // simulation-only; the real code generators don't care
                break;

            case INT_COMMENT:
                fprintf(f, "# %s", IntCode[i].name1);
                break;

            default:
                oops();
        }
        fprintf(f, "\n");
        fflush(f);
    }
    fclose(f);
}

//-----------------------------------------------------------------------------
// Convert a hex digit (0-9a-fA-F) to its hex value, or return -1 if the
// character is not a hex digit.
//-----------------------------------------------------------------------------
int HexDigit(int c)
{
    if((c >= '0') && (c <= '9')) {
        return c - '0';
    } else if((c >= 'a') && (c <= 'f')) {
        return 10 + (c - 'a');
    } else if((c >= 'A') && (c <= 'F')) {
        return 10 + (c - 'A');
    }
    return -1;
}

//-----------------------------------------------------------------------------
// Generate a unique symbol (unique with each call) having the given prefix
// guaranteed not to conflict with any user symbols.
//-----------------------------------------------------------------------------
static void GenSymParThis(char *dest)
{
    sprintf(dest, "$parThis_%04x", GenSymCountParThis);
    GenSymCountParThis++;
}
static void GenSymParOut(char *dest)
{
    sprintf(dest, "$parOut_%04x", GenSymCountParOut);
    GenSymCountParOut++;
}
static void GenSymOneShot(char *dest)
{
    sprintf(dest, "$oneShot_%04x", GenSymCountOneShot);
    GenSymCountOneShot++;
}
static void GenSymFormattedString(char *dest)
{
    sprintf(dest, "$formattedString_%04x", GenSymCountFormattedString);
    GenSymCountFormattedString++;
}

//-----------------------------------------------------------------------------
// Compile an instruction to the program.
//-----------------------------------------------------------------------------
static void Op(int op, char *name1, char *name2, char *name3, SWORD lit)
{
    IntCode[IntCodeLen].op = op;
    if(name1) strcpy(IntCode[IntCodeLen].name1, name1);
    if(name2) strcpy(IntCode[IntCodeLen].name2, name2);
    if(name3) strcpy(IntCode[IntCodeLen].name3, name3);
    IntCode[IntCodeLen].literal = lit;
    IntCodeLen++;
}
static void Op(int op, char *name1, char *name2, SWORD lit)
{
    Op(op, name1, name2, NULL, lit);
}
static void Op(int op, char *name1, SWORD lit)
{
    Op(op, name1, NULL, NULL, lit);
}
static void Op(int op, char *name1, char *name2)
{
    Op(op, name1, name2, NULL, 0);
}
static void Op(int op, char *name1)
{
    Op(op, name1, NULL, NULL, 0);
}
static void Op(int op)
{
    Op(op, NULL, NULL, NULL, 0);
}

//-----------------------------------------------------------------------------
// Compile the instruction that the simulator uses to keep track of which
// nodes are energized (so that it can display which branches of the circuit
// are energized onscreen). The MCU code generators ignore this, of course.
//-----------------------------------------------------------------------------
static void SimState(BOOL *b, char *name)
{
    IntCode[IntCodeLen].op = INT_SIMULATE_NODE_STATE;
    strcpy(IntCode[IntCodeLen].name1, name);
    IntCode[IntCodeLen].poweredAfter = b;
    IntCodeLen++;
}

//-----------------------------------------------------------------------------
// printf-like comment function
//-----------------------------------------------------------------------------
void Comment(char *str, ...)
{
    va_list f;
    char buf[MAX_NAME_LEN];
    va_start(f, str);
    vsprintf(buf, str, f);
    Op(INT_COMMENT, buf);
}

//-----------------------------------------------------------------------------
// Calculate the period in scan units from the period in microseconds, and
// raise an error if the given period is unachievable.
//-----------------------------------------------------------------------------
static int TimerPeriod(ElemLeaf *l)
{
    int period = (l->d.timer.delay / Prog.cycleTime) - 1;

    if(period < 1)  {
        Error(_("Timer period too short (needs faster cycle time)."));
        CompileError();
    }
    if(period >= (1 << 15)) {
        Error(_("Timer period too long (max 32767 times cycle time); use a "
            "slower cycle time."));
        CompileError();
    }

    return period;
}

//-----------------------------------------------------------------------------
// Is an expression that could be either a variable name or a number a number?
//-----------------------------------------------------------------------------
static BOOL IsNumber(char *str)
{
    if(*str == '-' || isdigit(*str)) {
        return TRUE;
    } else if(*str == '\'') {
        // special case--literal single character
        return TRUE;
    } else {
        return FALSE;
    }
}

//-----------------------------------------------------------------------------
// Try to turn a string into a 16-bit constant, and raise an error if
// something bad happens when we do so (e.g. out of range).
//-----------------------------------------------------------------------------
SWORD CheckMakeNumber(char *str)
{
    int val;

    if(*str == '\'') {
        val = str[1];
    } else {
        val = atoi(str);
    }

    if(val < -32768 || val > 32767) {   
        Error(_("Constant %d out of range: -32768 to 32767 inclusive."), val);
        CompileError();
    }

    return (SWORD)val;
}

//-----------------------------------------------------------------------------
// Return an integer power of ten.
//-----------------------------------------------------------------------------
static int TenToThe(int x)
{
    int i;
    int r = 1;
    for(i = 0; i < x; i++) {
        r *= 10;
    }
    return r;
}

//-----------------------------------------------------------------------------
// Compile code to evaluate the given bit of ladder logic. The rung input
// state is in stateInOut before calling and will be in stateInOut after
// calling.
//-----------------------------------------------------------------------------
static char *VarFromExpr(char *expr, char *tempName)
{
    if(IsNumber(expr)) {
        Op(INT_SET_VARIABLE_TO_LITERAL, tempName, CheckMakeNumber(expr));
        return tempName;
    } else {
        return expr;
    }
}
static void IntCodeFromCircuit(int which, void *any, char *stateInOut)
{
    ElemLeaf *l = (ElemLeaf *)any;

    switch(which) {
        case ELEM_SERIES_SUBCKT: {
            int i;
            ElemSubcktSeries *s = (ElemSubcktSeries *)any;
            
            Comment("start series [");
            for(i = 0; i < s->count; i++) {
                IntCodeFromCircuit(s->contents[i].which, s->contents[i].d.any,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -