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

📄 interpret.c

📁 nedit 是一款linux下的开发源码的功能强大的编辑器
💻 C
📖 第 1 页 / 共 5 页
字号:
static const char CVSID[] = "$Id: interpret.c,v 1.33.2.1 2003/10/20 16:38:57 tringali Exp $";/********************************************************************************									       ** interpret.c -- Nirvana Editor macro interpreter			       **									       ** Copyright (C) 1999 Mark Edel						       **									       ** This 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 2 of the License, or (at your option) any later   ** version.							               ** 									       ** This software 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 ** software; if not, write to the Free Software Foundation, Inc., 59 Temple     ** Place, Suite 330, Boston, MA  02111-1307 USA		                       **									       ** Nirvana Text Editor	    						       ** April, 1997								       **									       ** Written by Mark Edel							       **									       ********************************************************************************/#ifdef HAVE_CONFIG_H#include "../config.h"#endif#include "interpret.h"#include "textBuf.h"#include "nedit.h"#include "menu.h"#include "text.h"#include "rbTree.h"#include <stdio.h>#include <stdlib.h>#include <string.h>#include <math.h>#include <limits.h>#include <ctype.h>#include <errno.h>#ifdef VMS#include "../util/VMSparam.h"#else#ifndef __MVS__#include <sys/param.h>#endif#endif /*VMS*/#include <X11/Intrinsic.h>#include <Xm/Xm.h>#ifdef HAVE_DEBUG_H#include "../debug.h"#endif#define PROGRAM_SIZE  4096	/* Maximum program size */#define MAX_ERR_MSG_LEN 256	/* Max. length for error messages */#define LOOP_STACK_SIZE 200	/* (Approx.) Number of break/continue stmts    	    	    	    	   allowed per program */#define INSTRUCTION_LIMIT 100 	/* Number of instructions the interpreter is    	    	    	    	   allowed to execute before preempting and    	    	    	    	   returning to allow other things to run *//* Temporary markers placed in a branch address location to designate   which loop address (break or continue) the location needs */#define NEEDS_BREAK (Inst)1#define NEEDS_CONTINUE (Inst)2#define N_ARGS_ARG_SYM -1   	/* special arg number meaning $n_args value */enum opStatusCodes {STAT_OK=2, STAT_DONE, STAT_ERROR, STAT_PREEMPT};static void addLoopAddr(Inst *addr);static void saveContext(RestartData *context);static void restoreContext(RestartData *context);static int returnNoVal(void);static int returnVal(void);static int returnValOrNone(int valOnStack);static int pushSymVal(void);static int pushArraySymVal(void);static int dupStack(void);static int add(void);static int subtract(void);static int multiply(void);static int divide(void);static int modulo(void);static int negate(void);static int increment(void);static int decrement(void);static int gt(void);static int lt(void);static int ge(void);static int le(void);static int eq(void);static int ne(void);static int bitAnd(void);static int bitOr(void);static int and(void);static int or(void);static int not(void);static int power(void);static int concat(void);static int assign(void);static int callSubroutine(void);static int fetchRetVal(void);static int branch(void);static int branchTrue(void);static int branchFalse(void);static int branchNever(void);static int arrayRef(void);static int arrayAssign(void);static int arrayRefAndAssignSetup(void);static int beginArrayIter(void);static int arrayIter(void);static int inArray(void);static int deleteArrayElement(void);static void freeSymbolTable(Symbol *symTab);static int errCheck(const char *s);static int execError(const char *s1, const char *s2);static rbTreeNode *arrayEmptyAllocator(void);static rbTreeNode *arrayAllocateNode(rbTreeNode *src);static int arrayEntryCopyToNode(rbTreeNode *dst, rbTreeNode *src);static int arrayEntryCompare(rbTreeNode *left, rbTreeNode *right);static void arrayDisposeNode(rbTreeNode *src);static SparseArrayEntry *allocateSparseArrayEntry(void);/*#define DEBUG_ASSEMBLY*//*#define DEBUG_STACK*/#if defined(DEBUG_ASSEMBLY) || defined(DEBUG_STACK)#define DEBUG_DISASSEMBLERstatic void disasm(Inst *inst, int nInstr);#endif /* #if defined(DEBUG_ASSEMBLY) || defined(DEBUG_STACK) */#ifdef DEBUG_ASSEMBLY   /* for disassembly */#define DISASM(i, n)    disasm(i, n)#else /* #ifndef DEBUG_ASSEMBLY */#define DISASM(i, n)#endif /* #ifndef DEBUG_ASSEMBLY */#ifdef DEBUG_STACK      /* for run-time instruction and stack trace */static void stackdump(int n, int extra);#define STACKDUMP(n, x) stackdump(n, x)#define DISASM_RT(i, n) disasm(i, n)#else /* #ifndef DEBUG_STACK */#define STACKDUMP(n, x)#define DISASM_RT(i, n)#endif /* #ifndef DEBUG_STACK *//* Global symbols and function definitions */static Symbol *GlobalSymList = NULL;/* List of all memory allocated for strings */static char *AllocatedStrings = NULL;typedef struct {    SparseArrayEntry 	data; /* LEAVE this as top entry */    int inUse;              /* we use pointers to the data to refer to the entire struct */    struct SparseArrayEntryWrapper *next;} SparseArrayEntryWrapper;static SparseArrayEntryWrapper *AllocatedSparseArrayEntries = NULL; /* Message strings used in macros (so they don't get repeated every time   the macros are used */static const char *StackOverflowMsg = "macro stack overflow";static const char *StackUnderflowMsg = "macro stack underflow";static const char *StringToNumberMsg = "string could not be converted to number";/* Temporary global data for use while accumulating programs */static Symbol *LocalSymList = NULL;	 /* symbols local to the program */static Inst Prog[PROGRAM_SIZE]; 	 /* the program */static Inst *ProgP;			 /* next free spot for code gen. */static Inst *LoopStack[LOOP_STACK_SIZE]; /* addresses of break, cont stmts */static Inst **LoopStackPtr = LoopStack;  /*  to fill at the end of a loop *//* Global data for the interpreter */static DataValue *Stack;	    /* the stack */static DataValue *StackP;	    /* next free spot on stack */static DataValue *FrameP;   	    /* frame pointer (start of local variables    	    	    	    	       for the current subroutine invocation) */static Inst *PC;		    /* program counter during execution */static char *ErrMsg;		    /* global for returning error messages    	    	    	    	       from executing functions */static WindowInfo	*InitiatingWindow = NULL;   /* window from which macro was run */static WindowInfo *FocusWindow;	    /* window on which macro commands operate */static int PreemptRequest;  	    /* passes preemption requests from called    	    	    	    	       routines back up to the interpreter *//* Array for mapping operations to functions for performing the operations   Must correspond to the enum called "operations" in interpret.h */static int (*OpFns[N_OPS])() = {returnNoVal, returnVal, pushSymVal, dupStack,    add, subtract, multiply, divide, modulo, negate, increment, decrement,    gt, lt, ge, le, eq, ne, bitAnd, bitOr, and, or, not, power, concat,    assign, callSubroutine, fetchRetVal, branch, branchTrue, branchFalse,    branchNever, arrayRef, arrayAssign, beginArrayIter, arrayIter, inArray,    deleteArrayElement, pushArraySymVal,    arrayRefAndAssignSetup};/*** Initialize macro language global variables.  Must be called before** any macros are even parsed, because the parser uses action routine** symbols to comprehend hyphenated names.*/void InitMacroGlobals(void){    XtActionsRec *actions;    int i, nActions;    static char argName[3] = "$x";    static DataValue dv = {NO_TAG, {0}};    /* Add action routines from NEdit menus and text widget */    actions = GetMenuActions(&nActions);    for (i=0; i<nActions; i++) {    	dv.val.xtproc = actions[i].proc;    	InstallSymbol(actions[i].string, ACTION_ROUTINE_SYM, dv);    }    actions = TextGetActions(&nActions);    for (i=0; i<nActions; i++) {    	dv.val.xtproc = actions[i].proc;    	InstallSymbol(actions[i].string, ACTION_ROUTINE_SYM, dv);    }        /* Add subroutine argument symbols ($1, $2, ..., $9) */    for (i=0; i<9; i++) {	argName[1] = '1' + i;	dv.val.n = i;	InstallSymbol(argName, ARG_SYM, dv);    }        /* Add special symbol $n_args */    dv.val.n = N_ARGS_ARG_SYM;    InstallSymbol("$n_args", ARG_SYM, dv);}/*** To build a program for the interpreter, call BeginCreatingProgram, to** begin accumulating the program, followed by calls to AddOp, AddSym,** and InstallSymbol to add symbols and operations.  When the new program** is finished, collect the results with FinishCreatingProgram.  This returns** a self contained program that can be run with ExecuteMacro.*//*** Start collecting instructions for a program. Clears the program** and the symbol table.*/void BeginCreatingProgram(void){     LocalSymList = NULL;    ProgP = Prog;    LoopStackPtr = LoopStack;}/*** Finish up the program under construction, and return it (code and** symbol table) as a package that ExecuteMacro can execute.  This** program must be freed with FreeProgram.*/Program *FinishCreatingProgram(void){    Program *newProg;    int progLen, fpOffset = 0;    Symbol *s;        newProg = (Program *)XtMalloc(sizeof(Program));    progLen = ((char *)ProgP) - ((char *)Prog);    newProg->code = (Inst *)XtMalloc(progLen);    memcpy(newProg->code, Prog, progLen);    newProg->localSymList = LocalSymList;    LocalSymList = NULL;        /* Local variables' values are stored on the stack.  Here we assign       frame pointer offsets to them. */    for (s = newProg->localSymList; s != NULL; s = s->next)	s->value.val.n = fpOffset++;        DISASM(newProg->code, ProgP - Prog);        return newProg;}void FreeProgram(Program *prog){    freeSymbolTable(prog->localSymList);    XtFree((char *)prog->code);    XtFree((char *)prog);    }/*** Add an operator (instruction) to the end of the current program*/int AddOp(int op, char **msg){    if (ProgP >= &Prog[PROGRAM_SIZE]) {	*msg = "macro too large";	return 0;    }    *ProgP++ = OpFns[op];    return 1;}/*** Add a symbol operand to the current program*/int AddSym(Symbol *sym, char **msg){    if (ProgP >= &Prog[PROGRAM_SIZE]) {	*msg = "macro too large";	return 0;    }    *ProgP++ = (Inst)sym;    return 1;}/*** Add an immediate value operand to the current program*/int AddImmediate(void *value, char **msg){    if (ProgP >= &Prog[PROGRAM_SIZE]) {	*msg = "macro too large";	return 0;    }    *ProgP++ = (Inst)value;    return 1;}/*** Add a branch offset operand to the current program*/int AddBranchOffset(Inst *to, char **msg){    if (ProgP >= &Prog[PROGRAM_SIZE]) {	*msg = "macro too large";	return 0;    }    *ProgP = (Inst)(to - ProgP);    ProgP++;        return 1;}/*** Return the address at which the next instruction will be stored*/Inst *GetPC(void){    return ProgP;}/*** Swap the positions of two contiguous blocks of code.  The first block** running between locations start and boundary, and the second between** boundary and end.*/void SwapCode(Inst *start, Inst *boundary, Inst *end){#define reverseCode(L, H) \    do { register Inst t, *l = L, *h = H - 1; \         while (l < h) { t = *h; *h-- = *l; *l++ = t; } } while (0)    /* double-reverse method: reverse elements of both parts then whole lot */    /* eg abcdefABCD -1-> edcbaABCD -2-> edcbaDCBA -3-> DCBAedcba */    reverseCode(start, boundary);   /* 1 */    reverseCode(boundary, end);     /* 2 */    reverseCode(start, end);        /* 3 */}/*** Maintain a stack to save addresses of branch operations for break and** continue statements, so they can be filled in once the information** on where to branch is known.**** Call StartLoopAddrList at the beginning of a loop, AddBreakAddr or** AddContinueAddr to register the address at which to store the branch** address for a break or continue statement, and FillLoopAddrs to fill** in all the addresses and return to the level of the enclosing loop.*/void StartLoopAddrList(void){    addLoopAddr(NULL);}int AddBreakAddr(Inst *addr){    if (LoopStackPtr == LoopStack) return 1;    addLoopAddr(addr);    *addr = NEEDS_BREAK;    return 0;}int AddContinueAddr(Inst *addr){       if (LoopStackPtr == LoopStack) return 1;    addLoopAddr(addr);    *addr = NEEDS_CONTINUE;    return 0;}static void addLoopAddr(Inst *addr){    if (LoopStackPtr > &LoopStack[LOOP_STACK_SIZE-1]) {    	fprintf(stderr, "NEdit: loop stack overflow in macro parser");    	return;    }    *LoopStackPtr++ = addr;}void FillLoopAddrs(Inst *breakAddr, Inst *continueAddr){    while (True) {    	LoopStackPtr--;    	if (LoopStackPtr < LoopStack) {    	    fprintf(stderr, "NEdit: internal error (lsu) in macro parser\n");    	    return;    	}    	if (*LoopStackPtr == NULL)    	    break;    	if (**LoopStackPtr == NEEDS_BREAK)    	    **(Inst ***)LoopStackPtr = (Inst *)(breakAddr - *LoopStackPtr);    	else if (**LoopStackPtr == NEEDS_CONTINUE)    	    **(Inst ***)LoopStackPtr = (Inst *)(continueAddr - *LoopStackPtr);    	else    	    fprintf(stderr, "NEdit: internal error (uat) in macro parser\n");    }}/*** Execute a compiled macro, "prog", using the arguments in the array** "args".  Returns one of MACRO_DONE, MACRO_PREEMPT, or MACRO_ERROR.** if MACRO_DONE is returned, the macro completed, and the returned value** (if any) can be read from "result".  If MACRO_PREEMPT is returned, the** macro exceeded its alotted time-slice and scheduled...*/int ExecuteMacro(WindowInfo *window, Program *prog, int nArgs, DataValue *args,    	DataValue *result, RestartData **continuation, char **msg){    RestartData *context;    static DataValue noValue = {NO_TAG, {0}};    Symbol *s;    int i;        /* Create an execution context (a stack, a stack pointer, a frame pointer,       and a program counter) which will retain the program state across       preemption and resumption of execution */    context = (RestartData *)XtMalloc(sizeof(RestartData));    context->stack = (DataValue *)XtMalloc(sizeof(DataValue) * STACK_SIZE);    *continuation = context;    context->stackP = context->stack;    context->pc = prog->code;    context->runWindow = window;    context->focusWindow = window;    /* Push arguments and call information onto the stack */    for (i=0; i<nArgs; i++)    	*(context->stackP++) = args[i];

⌨️ 快捷键说明

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