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

📄 codegen.c

📁 Calc Software Package for Number Calc
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * codegen - module to generate opcodes from the input tokens * * Copyright (C) 1999-2006  David I. Bell and Ernest Bowen * * Primary author:  David I. Bell * * Calc is open software; you can redistribute it and/or modify it under * the terms of the version 2.1 of the GNU Lesser General Public License * as published by the Free Software Foundation. * * Calc 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 Lesser General * Public License for more details. * * A copy of version 2.1 of the GNU Lesser General Public License is * distributed with calc under the filename COPYING-LGPL.  You should have * received a copy with calc; if not, write to Free Software Foundation, Inc. * 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA. * * @(#) $Revision: 29.22 $ * @(#) $Id: codegen.c,v 29.22 2006/12/15 16:25:09 chongo Exp $ * @(#) $Source: /usr/local/src/cmd/calc/RCS/codegen.c,v $ * * Under source code control:	1990/02/15 01:48:13 * File existed as early as:	before 1990 * * Share and enjoy!  :-)	http://www.isthe.com/chongo/tech/comp/calc/ */#include <stdio.h>#include "have_unistd.h"#if defined(HAVE_UNISTD_H)#include <unistd.h>#endif#include "calc.h"#include "token.h"#include "symbol.h"#include "label.h"#include "opcodes.h"#include "string.h"#include "func.h"#include "conf.h"#if defined(_WIN32) && !defined(__CYGWIN__)# include <direct.h>#endifstatic BOOL rdonce;	/* TRUE => do not reread this file */FUNC *curfunc;static int getsymvalue(char *name, VALUE *v_p);static int getfilename(char *name, size_t namelen, BOOL *once);static BOOL getid(char *buf);static void getshowstatement(void);static void getfunction(void);static void ungetfunction(void);static void getbody(LABEL *contlabel, LABEL *breaklabel,		    LABEL *nextcaselabel, LABEL *defaultlabel);static int getdeclarations(int symtype);static int getsimpledeclaration (int symtype);static int getonevariable (int symtype);static void getstatement(LABEL *contlabel, LABEL *breaklabel,			 LABEL *nextcaselabel, LABEL *defaultlabel);static void getobjdeclaration(int symtype);static void getoneobj(long index, int symtype);static void getobjvars(char *name, int symtype);static void getmatdeclaration(int symtype);static void getonematrix(int symtype);static void creatematrix(void);static void getsimplebody(void);static void getcondition(void);static void getmatargs(void);static void getelement(void);static void usesymbol(char *name, int autodef);static void definesymbol(char *name, int symtype);static void getcallargs(char *name);static void do_changedir(void);static int getexprlist(void);static int getopassignment(void);static int getassignment(void);static int getaltcond(void);static int getorcond(void);static int getandcond(void);static int getrelation(void);static int getsum(void);static int getproduct(void);static int getorexpr(void);static int getandexpr(void);static int getshiftexpr(void);static int getreference(void);static int getincdecexpr(void);static int getterm(void);static int getidexpr(BOOL okmat, int autodef);static long getinitlist(void);#define INDICALLOC 8static int quickindices[INDICALLOC];static int * newindices;static int * indices;static int maxindices;/* * Read all the commands from an input file. * These are either declarations, or else are commands to execute now. * In general, commands are terminated by newlines or semicolons. * Exceptions are function definitions and escaped newlines. * Commands are read and executed until the end of file. * The toplevel flag indicates whether we are at the top interactive level. */voidgetcommands(BOOL toplevel){	char name[MAXCMD+1+1];	/* program name */	/* firewall */	name[0] = '\0';	name[MAXCMD+1] = '\0';	abort_now = FALSE;	/* getcommands */	if (!toplevel)		enterfilescope();	for (;;) {		int i;		(void) tokenmode(TM_NEWLINES);		switch (gettoken()) {		case T_DEFINE:			getfunction();			break;		case T_EOF:			if (!toplevel)				exitfilescope();			return;		case T_HELP:			for (i=1;;i++) {				switch(getfilename(name, MAXCMD+1, NULL)) {				case 1:				case -1:					if(i == 1) {						strcpy(name, DEFAULTCALCHELP);						givehelp(name);					}					break;				case 0:					givehelp(name);					continue;				default:					break;				}				break;			}			break;		case T_READ:			if (!allow_read) {				scanerror(T_NULL,				    "read command disallowed by -m mode\n");				break;			}			for (;;) {				int open_ret;				if (getfilename(name, MAXCMD+1, &rdonce))					break;				open_ret = opensearchfile(name,calcpath,						          CALCEXT,rdonce);				switch (open_ret) {				case 0:					getcommands(FALSE);					closeinput();					continue;				case 1:					/* prev read and -once was given */					continue;				case -2:					scanerror(T_NULL,						 "Maximum input depth reached");					break;				default:					scanerror(T_NULL,						  "Cannot open \"%s\"", name);					continue;				}				break;			}			break;		case T_WRITE:			if (!allow_write) {				scanerror(T_NULL,				    "write command disallowed by -m mode\n");				break;			}			if (getfilename(name, MAXCMD+1, NULL))				break;			if (writeglobals(name)) {				scanerror(T_NULL,					  "Error writing \"%s\"\n", name);			}			break;		case T_CD:			do_changedir();			break;		case T_NEWLINE:		case T_SEMICOLON:			break;		default:			rescantoken();			initstack();			if (evaluate(FALSE))				updateoldvalue(curfunc);			freefunc(curfunc);			if (abort_now) {				if (!stdin_tty)					run_state = RUN_EXIT;				else if (run_state < RUN_PRE_TOP_LEVEL)				run_state = RUN_PRE_TOP_LEVEL;				longjmp(jmpbuf, 1);			}		}	}}/* * Evaluate a line of statements. * This is done by treating the current line as a function body, * compiling it, and then executing it.	 Returns TRUE if the line * successfully compiled and executed.	The last expression result * is saved in the f_savedvalue element of the current function. * The nestflag variable should be FALSE for the outermost evaluation * level, and TRUE for all other calls (such as the 'eval' function). * The function name begins with an asterisk to indicate specialness. * * given: *	nestflag		TRUE if this is a nested evaluation */BOOLevaluate(BOOL nestflag){	char *funcname;	int loop = 1;		/* 0 => end the main while loop */	funcname = (nestflag ? "**" : "*");	beginfunc(funcname, nestflag);	if (gettoken() == T_LEFTBRACE) {		getbody(NULL_LABEL, NULL_LABEL, NULL_LABEL, NULL_LABEL);	} else {		if (nestflag)			(void) tokenmode(TM_DEFAULT);		rescantoken();		while (loop) {			switch (gettoken()) {			case T_SEMICOLON:				break;			case T_NEWLINE:			case T_EOF:				loop = 0;				break;			default:				rescantoken();				getstatement(NULL_LABEL, NULL_LABEL,					NULL_LABEL, NULL_LABEL);			}		}	}	addop(OP_UNDEF);	addop(OP_RETURN);	checklabels();	if (errorcount)		return FALSE;	calculate(curfunc, 0);	return TRUE;}/* * Undefine one or more functions */static voidungetfunction(void){	char *name;	int type;	for (;;) {		switch (gettoken()) {		case T_COMMA:			continue;		case T_SYMBOL:			name = tokensymbol();			type = getbuiltinfunc(name);			if (type >= 0) {				warning(			"Cannot undefine builtin function \"%s\"", name);			continue;			}			rmuserfunc(name);			continue;		case T_MULT:			rmalluserfunc();			continue;		case T_STATIC:			if (gettoken() != T_SYMBOL) {				scanerror(T_SEMICOLON,			 "Non-identifier following \"undefine static\"");				return;			}			name = tokensymbol();			endscope(name, FALSE);			continue;		case T_NEWLINE:		case T_SEMICOLON:		case T_EOF:			rescantoken();			return;		default:			scanerror(T_SEMICOLON, "Non-name arg for undefine");			return;		}	}}/* * Get a function declaration. * func = name '(' '' | name [ ',' name] ... ')' simplebody *	| name '(' '' | name [ ',' name] ... ')' body. */static voidgetfunction(void){	char *name;		/* parameter name */	int type;		/* type of token read */	LABEL label;	long index;	(void) tokenmode(TM_DEFAULT);	if (gettoken() != T_SYMBOL) {		scanerror(T_NULL, "Function name was expected");		return;	}	name = tokensymbol();	type = getbuiltinfunc(name);	if (type >= 0) {		scanerror(T_SEMICOLON, "Using builtin function name");		return;	}	beginfunc(name, FALSE);	enterfuncscope();	if (gettoken() != T_LEFTPAREN) {		scanerror(T_SEMICOLON,			"Left parenthesis expected for function");		return;	}	index = 0;	for (;;) {		type = gettoken();		if (type == T_RIGHTPAREN)			break;		if (type != T_SYMBOL) {			scanerror(T_COMMA,			"Using non-identifier as function parameter");			return;		}		name = tokensymbol();		switch (symboltype(name)) {		case SYM_UNDEFINED:		case SYM_GLOBAL:		case SYM_STATIC:			index = addparam(name);			break;		default:			scanerror(T_NULL,				  "Parameter \"%s\" is already defined",				  name);		}		type = gettoken();		if (type == T_ASSIGN) {			clearlabel(&label);			addopone(OP_PARAMADDR, index);			addoplabel(OP_JUMPNN, &label);			getopassignment();			addop(OP_ASSIGNPOP);			setlabel(&label);			type = gettoken();		}		if (type == T_RIGHTPAREN)			break;		if (type != T_COMMA) {			scanerror(T_COMMA,			"Using other than comma to separate parameters");			return;		}	}	switch (gettoken()) {	case T_ASSIGN:		getsimplebody();		break;	case T_LEFTBRACE:		getbody(NULL_LABEL, NULL_LABEL, NULL_LABEL,			NULL_LABEL);		break;	default:		scanerror(T_NULL,			"Left brace or equals sign expected for function");		return;	}	endfunc();	exitfuncscope();}/* * Get a simple assignment style body for a function declaration. * simplebody = '=' assignment '\n'. */static voidgetsimplebody(void){	(void) tokenmode(TM_NEWLINES);	(void) getexprlist();	addop(OP_RETURN);}/* * Get the body of a function, or a subbody of a function. * body = '{' [ declarations ] ... [ statement ] ... '}' *	| [ declarations ] ... [statement ] ... '\n' *//*ARGSUSED*/static voidgetbody(LABEL *contlabel, LABEL *breaklabel, LABEL *nextcaselabel, LABEL *defaultlabel){	int oldmode;	oldmode = tokenmode(TM_DEFAULT);	while (TRUE) {		switch (gettoken()) {		case T_RIGHTBRACE:			(void) tokenmode(oldmode);			return;		case T_EOF:			scanerror(T_NULL, "End-of-file in function body");			return;		default:			rescantoken();			getstatement(contlabel, breaklabel,				     nextcaselabel, defaultlabel);		}	}}/* * Get a line of possible local, global, or static variable declarations. * declarations = { LOCAL | GLOBAL | STATIC } onedeclaration *	[ ',' onedeclaration ] ... ';'. */static intgetdeclarations(int symtype){	int res = 0;	while (TRUE) {		switch (gettoken()) {		case T_COMMA:			continue;		case T_NEWLINE:		case T_SEMICOLON:		case T_RIGHTBRACE:		case T_EOF:			rescantoken();			return res;		case T_SYMBOL:			addopone(OP_DEBUG, linenumber());			rescantoken();			if (getsimpledeclaration(symtype))				res = 1;			break;		case T_MAT:			addopone(OP_DEBUG, linenumber());			getmatdeclaration(symtype);			res = 1;			break;		case T_OBJ:			addopone(OP_DEBUG, linenumber());			getobjdeclaration(symtype);			addop(OP_POP);			res = 1;			break;		default:			scanerror(T_SEMICOLON,				 "Bad syntax in declaration statement");			return res;		}	}}/* * Get declaration of a sequence of simple identifiers, as in *	global a, b = 1, c d = 2, d; * Subsequences end with "," or at end of line; spaces indicate * repeated assignment, e.g. "c d = 2" has the effect of "c = 2, d = 2". */static intgetsimpledeclaration(int symtype){	int res = 0;	for (;;) {		switch (gettoken()) {		case T_SYMBOL:			rescantoken();			if (getonevariable(symtype)) {				res = 1;				addop(OP_POP);			}			continue;		case T_COMMA:			continue;		default:			rescantoken();			return res;		}	}}/* * Get one variable in a sequence of simple identifiers. * Returns 1 if the subsequence in which the variable occurs ends with * an assignment, e.g. for the variables b, c, d, in *	static a, b = 1, c d = 2, d; */static intgetonevariable(int symtype){	char *name;	int res = 0;	switch(gettoken()) {	case T_SYMBOL:		name = addliteral(tokensymbol());		res = getonevariable(symtype);		definesymbol(name, symtype);		if (res) {			usesymbol(name, 0);			addop(OP_ASSIGNBACK);		}		return res;	case T_ASSIGN:		getopassignment();		rescantoken();		return 1;	default:		rescantoken();		return 0;	}}/* * Get a statement. * statement = IF condition statement [ELSE statement] *	| FOR '(' [assignment] ';' [assignment] ';' [assignment] ')' statement *	| WHILE condition statement *	| DO statement WHILE condition ';' *	| SWITCH condition '{' [caseclause] ... '}' *	| CONTINUE ';' *	| BREAK ';' *	| RETURN assignment ';' *	| GOTO label ';' *	| PRINT assignment [, assignment ] ... ';' *	| QUIT [ string ] ';' *	| ABORT [ string ] ';' *	| SHOW item ';' *	| body *	| assignment ';' *	| label ':' statement *	| ';'. * * given: *	contlabel		label for continue statement *	breaklabel		label for break statement *	nextcaselabel		label for next case statement *	defaultlabel		label for default case */static voidgetstatement(LABEL *contlabel, LABEL *breaklabel, LABEL *nextcaselabel, LABEL *defaultlabel){	LABEL label;	LABEL label1, label2, label3, label4;	/* locations for jumps */	int type;	BOOL printeol;	int oldmode;	addopone(OP_DEBUG, linenumber());	switch (gettoken()) {	case T_NEWLINE:	case T_SEMICOLON:		return;	case T_GLOBAL:		(void) getdeclarations(SYM_GLOBAL);		break;	case T_STATIC:		clearlabel(&label);		addoplabel(OP_INITSTATIC, &label);		if (getdeclarations(SYM_STATIC))			setlabel(&label);		else			curfunc->f_opcodecount -= 2;		break;	case T_LOCAL:		(void) getdeclarations(SYM_LOCAL);		break;	case T_UNDEFINE:		ungetfunction();		break;	case T_RIGHTBRACE:		scanerror(T_NULL, "Extraneous right brace");		return;	case T_CONTINUE:		if (contlabel == NULL_LABEL) {			scanerror(T_SEMICOLON,				  "CONTINUE not within FOR, WHILE, or DO");			return;		}		addoplabel(OP_JUMP, contlabel);		break;	case T_BREAK:		if (breaklabel == NULL_LABEL) {			scanerror(T_SEMICOLON,				  "BREAK not within FOR, WHILE, or DO");			return;		}		addoplabel(OP_JUMP, breaklabel);		break;	case T_GOTO:		if (gettoken() != T_SYMBOL) {			scanerror(T_SEMICOLON, "Missing label in goto");			return;		}		addop(OP_JUMP);		addlabel(tokensymbol());		break;	case T_RETURN:		switch (gettoken()) {		case T_NEWLINE:		case T_SEMICOLON:			addop(OP_UNDEF);			addop(OP_RETURN);			return;		default:			rescantoken();			(void) getexprlist();			if (curfunc->f_name[0] == '*')				addop(OP_SAVE);			addop(OP_RETURN);		}		break;	case T_LEFTBRACE:		getbody(contlabel, breaklabel, nextcaselabel, defaultlabel);		return;	case T_IF:		clearlabel(&label1);		clearlabel(&label2);		getcondition();		switch(gettoken()) {		case T_CONTINUE:			if (contlabel == NULL_LABEL) {

⌨️ 快捷键说明

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