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

📄 codegen.c

📁 Calc Software Package for Number Calc
💻 C
📖 第 1 页 / 共 4 页
字号:
		getobjdeclaration(SYM_UNDEFINED);		type = EXPR_ASSIGN;		break;	case T_SYMBOL:		rescantoken();		type = getidexpr(TRUE, 0);		break;	case T_MULT:		(void) getterm();		addop(OP_DEREF);		type = 0;		break;	case T_POWER:			/* '**' or '^' */		(void) getterm();		addop(OP_DEREF);		addop(OP_DEREF);		type = 0;		break;	case T_GLOBAL:		if (gettoken() != T_SYMBOL) {			scanerror(T_NULL,				 "No identifier after global specifier");			break;		}		rescantoken();		type = getidexpr(TRUE, T_GLOBAL);		break;	case T_LOCAL:		if (gettoken() != T_SYMBOL) {			scanerror(T_NULL,				 "No identifier after local specifier");			break;		}		rescantoken();		type = getidexpr(TRUE, T_LOCAL);		break;	case T_STATIC:		if (gettoken() != T_SYMBOL) {			scanerror(T_NULL,				 "No identifier after static specifier");			break;		}		rescantoken();		type = getidexpr(TRUE, T_STATIC);		break;	case T_LEFTBRACKET:		scanerror(T_NULL, "Left bracket with no preceding lvalue");		break;	case T_PERIOD:		scanerror(T_NULL, "Period with no preceding lvalue");		break;	default:		if (iskeyword(type)) {			scanerror(T_NULL,			    "Expression contains reserved keyword");			break;		}		rescantoken();		scanerror(T_COMMA, "Missing expression");	}	if (type == 0) {		for (;;) {			switch (gettoken()) {			case T_LEFTBRACKET:				rescantoken();				getmatargs();				type = 0;				break;			case T_PERIOD:				getelement();				type = 0;				break;			case T_LEFTPAREN:				scanerror(T_NULL,					  "Function calls not allowed "					  "as expressions");			default:				rescantoken();			return type;			}		}	}	return type;}/* * Read in an identifier expressions. * This is a symbol name followed by parenthesis, or by square brackets or * element references.  The symbol can be a global or a local variable name. * Returns the type of expression found. */static intgetidexpr(BOOL okmat, int autodef){	int type;	char name[SYMBOLSIZE+1];	/* symbol name */	int oldmode;	type = 0;	if (!getid(name))		return type;	switch (gettoken()) {	case T_LEFTPAREN:		oldmode = tokenmode(TM_DEFAULT);		getcallargs(name);		(void) tokenmode(oldmode);		type = 0;		break;	case T_ASSIGN:		if (autodef != T_GLOBAL && autodef != T_LOCAL &&				autodef != T_STATIC)			autodef = 1;		/* fall into default case */	default:		rescantoken();		usesymbol(name, autodef);	}	/*	 * Now collect as many element references and matrix index operations	 * as there are following the id.	 */	for (;;) {		switch (gettoken()) {		case T_LEFTBRACKET:			rescantoken();			if (!okmat)				return type;			getmatargs();			type = 0;			break;		case T_ARROW:			addop(OP_DEREF);			/*FALLTHRU*/		case T_PERIOD:			getelement();			type = 0;			break;		case T_LEFTPAREN:			scanerror(T_NULL,				  "Function calls not allowed "				  "as expressions");		default:			rescantoken();			return type;		}	}}/* * getsymvalue - return the VALUE of a symbol * * given: *	name	symbol name *	v_p	pointer to value return * * returns: *	symbol type found: * *		SYM_UNDEFINED	no such symbol *		SYM_GLOBAL	global symbol found * * NOTE: This is a special hack to allow some special code in getfilename() *	 to get the value of a symbol.  It should NOT be used in the *	 general op code generation / calc code parsing case. */static intgetsymvalue(char *name, VALUE *v_p){	GLOBAL *g_ret;		/* global return from findglobal() */	/* firewall */	if (name == NULL || v_p == NULL) {		return SYM_UNDEFINED;	}	/* look for a global */	g_ret = findglobal(name);	if (g_ret != NULL) {		*v_p = g_ret->g_value;		return SYM_GLOBAL;	}	/* no such symbol */	return SYM_UNDEFINED;}/* * Read in a filename for a read or write command. * Both quoted and unquoted filenames are handled here. * The name must be terminated by an end of line or semicolon. * Returns TRUE if the filename was successfully parsed. * * given: *	name		filename to read *	namelen		length of filename buffer including NUL byte *	once		non-NULL => set to TRUE of -once read */static intgetfilename(char *name, size_t namelen, BOOL *once){	STRING *s;	char *symstr;	/* symbol string */	VALUE val;	/* value of the symbol */	int i;	(void) tokenmode(TM_NEWLINES | TM_ALLSYMS);	for (i = 2; i > 0; i--) {		switch (gettoken()) {		case T_STRING:			/* use the value of the literal string */			s = findstring(tokenstring());			strncpy(name, s->s_str, namelen-1);			name[namelen-1] = '\0';			sfree(s);			break;		case T_SYMBOL:			/* get the symbol name */			symstr = tokensymbol();			/*			 * special hack - symbols starting with $ are			 *		  treated as a global variable			 *		  instead of a literal string.			 */			if (symstr[0] == '$') {				++symstr;				if (getsymvalue(symstr, &val)) {					if (val.v_type == V_STR) {						/* use symbol VALUE string */						symstr = val.v_str->s_str;						if (symstr == NULL) {							math_error("string value pointer is NULL!!");							/*NOTREACHED*/						}					} else {						math_error("a filename variable must be a string");						/*NOTREACHED*/					}				} else {					math_error("no such global variable");					/*NOTREACHED*/				}			}			/* return symbol name or value of global var string */			strncpy(name, symstr, namelen-1);			name[namelen-1] = '\0';			break;		case T_NEWLINE:			/* found newline */			rescantoken();			return 1;		default:			/* found something unexpected */			rescantoken();			return -1;		}		/* deal with -once */		if (i == 2 && once != NULL) {			if ((*once = !strcmp(name, "-once")))				continue;		}		break;	}	return 0;}/* * Read the show command to display useful information */static voidgetshowstatement(void){	char name[5];	long arg, index;	switch (gettoken()) {	case T_SYMBOL:		strncpy(name, tokensymbol(), 4);		name[4] = '\0';		/* Yuck! */		arg = stringindex("buil\000"				  "real\000"				  "func\000"				  "objf\000"				  "conf\000"				  "objt\000"				  "file\000"				  "size\000"				  "erro\000"				  "cust\000"				  "bloc\000"				  "cons\000"				  "glob\000"				  "stat\000"				  "numb\000"				  "redc\000"				  "stri\000"				  "lite\000"				  "opco\000", name);		break;	case T_GLOBAL:		arg = 13; break;	case T_STATIC:		arg = 14; break;	default:		printf("SHOW command to be followed by at least ");		printf("four letters of one of:\n");		printf("\tblocks, builtin, config, constants, ");		printf("custom, errors, files, functions,\n");		printf("\tglobaltypes, objfunctions, objtypes, "		       "opcodes, sizes, ");		printf("realglobals,\n");		printf("\tstatics, numbers, redcdata, "		       "strings, literals\n");		rescantoken();		return;	}	if (arg == 19) {		if (gettoken() != T_SYMBOL) {			rescantoken();			scanerror(T_SEMICOLON,				  "Function name expected for show statement");			return;		}		index = adduserfunc(tokensymbol());		addopone(OP_SHOW, index + 19);		return;	}	if (arg > 0)		addopone(OP_SHOW, arg);	else		warning("Unknown parameter for show statement");}/* * Read in a set of matrix index arguments, surrounded with square brackets. * This also handles double square brackets for 'fast indexing'. */static voidgetmatargs(void){	int dim;	if (gettoken() != T_LEFTBRACKET) {		scanerror(T_NULL, "Matrix indexing expected");		return;	}	/*	 * Parse all levels of the array reference	 * Look for the 'fast index' first.	 */	if (gettoken() == T_LEFTBRACKET) {		(void) getopassignment();		if ((gettoken() != T_RIGHTBRACKET) ||			(gettoken() != T_RIGHTBRACKET)) {				scanerror(T_NULL, "Bad fast index usage");				return;		}		addop(OP_FIADDR);		return;	}	rescantoken();	/*	 * Normal indexing with the indexes separated by commas.	 * Initialize the flag in the opcode to assume that the array	 * element will only be referenced for reading.	 If the parser	 * finds that the element will be referenced for writing, then	 * it will call writeindexop to change the flag in the opcode.	 */	dim = 0;	if (gettoken() == T_RIGHTBRACKET) {		addoptwo(OP_INDEXADDR, (long) dim, (long) FALSE);		return;	}	rescantoken();	for (;;) {		++dim;		(void) getopassignment();		switch (gettoken()) {		case T_RIGHTBRACKET:			addoptwo(OP_INDEXADDR, (long) dim,					(long) FALSE);			return;		case T_COMMA:			break;		default:			rescantoken();			scanerror(T_NULL,				  "Missing right bracket in "				  "array reference");			return;		}	}}/* * Get an element of an object reference. * The leading period which introduces the element has already been read. */static voidgetelement(void){	long index;	char name[SYMBOLSIZE+1];	if (!getid(name))		return;	index = findelement(name);	if (index < 0) {		scanerror(T_NULL, "Element \"%s\" is undefined", name);		return;	}	addopone(OP_ELEMADDR, index);}/* * Read in a single symbol name and copy its value into the given buffer. * Returns TRUE if a valid symbol id was found. */static BOOLgetid(char *buf){	int type;	type = gettoken();	if (iskeyword(type)) {		scanerror(T_NULL, "Reserved keyword used as symbol name");		type = T_SYMBOL;		*buf = '\0';		return FALSE;	}	if (type != T_SYMBOL) {		rescantoken();		scanerror(T_NULL, "Symbol name expected");		*buf = '\0';		return FALSE;	}	strncpy(buf, tokensymbol(), SYMBOLSIZE);	buf[SYMBOLSIZE] = '\0';	return TRUE;}/* * Define a symbol name to be of the specified symbol type.  The scope * of a static variable with the same name is terminated if symtype is * global or if symtype is static and the old variable is at the same * level.  Warnings are issued when a global or local variable is * redeclared and when in the same body the variable will be accessible only ^ with the appropriate specfier. */static voiddefinesymbol(char *name, int symtype){	switch (symboltype(name)) {	case SYM_STATIC:		if (symtype == SYM_GLOBAL || symtype == SYM_STATIC)			endscope(name, symtype == SYM_GLOBAL);		break;	case SYM_GLOBAL:		if (symtype == SYM_GLOBAL && conf->redecl_warn) {			warning("redeclaraion of global \"%s\"",				name);			return;		}		break;	case SYM_LOCAL:		if (symtype == SYM_LOCAL && conf->redecl_warn) {			warning("redeclaraion of local \"%s\"",				name);			return;		}		if (symtype == SYM_GLOBAL && conf->dupvar_warn) {			warning("both local and global \"%s\" defined", name);			break;		}		if (conf->dupvar_warn) {			warning("both local and static \"%s\" defined", name);		}		break;	case SYM_PARAM:		if (symtype == SYM_LOCAL && conf->dupvar_warn) {			warning("both local and parameter \"%s\" defined",				name);			break;		}		if (symtype == SYM_GLOBAL && conf->dupvar_warn) {			warning("both global and parameter \"%s\" defined",				name);			break;		}		if (conf->dupvar_warn) {			warning("both static and parameter \"%s\" defined", name);		}	}	if (symtype == SYM_LOCAL)		(void) addlocal(name);	else		(void) addglobal(name, (symtype == SYM_STATIC));}/* * Check a symbol name to see if it is known and generate code to reference it. * The symbol can be either a parameter name, a local name, or a global name. * If autodef is true, we automatically define the name as a global symbol * if it is not yet known. * * given: *	name		symbol name to be checked *	autodef		1 => define if symbol is not known *			T_GLOBAL => get global, define if necessary */static voidusesymbol(char *name, int autodef){	int type;	type = symboltype(name);	if (autodef == T_GLOBAL) {		if (type == SYM_GLOBAL) {			warning("Unnecessary global specifier");		}		addopptr(OP_GLOBALADDR, (char *) addglobal(name, FALSE));		return;	}	if (autodef == T_STATIC) {		addopptr(OP_GLOBALADDR, (char *) addglobal(name, TRUE));		return;	}	if (autodef == T_LOCAL) {		if (type == SYM_LOCAL) {			warning("Unnecessary local specifier");		}		addopone(OP_LOCALADDR, addlocal(name));		return;	}	switch (type) {	case SYM_LOCAL:		addopone(OP_LOCALADDR, (long) findlocal(name));		return;	case SYM_PARAM:		addopone(OP_PARAMADDR, (long) findparam(name));		return;	case SYM_GLOBAL:	case SYM_STATIC:		addopptr(OP_GLOBALADDR, (char *) findglobal(name));		return;	}	/*	 * The symbol is not yet defined.	 * If we are at the top level and we are allowed to, then define it.	 */	if ((curfunc->f_name[0] != '*') || !autodef) {		scanerror(T_NULL, "\"%s\" is undefined", name);		return;	}	(void) addglobal(name, FALSE);	addopptr(OP_GLOBALADDR, (char *) findglobal(name));}/* * Get arguments for a function call. * The name and beginning parenthesis has already been seen. * callargs = [ [ '&' ] assignment  [',' [ '&' ] assignment] ] ')'. * * given: *	name		name of function */static voidgetcallargs(char *name){	long index;		/* function index */	long op;		/* opcode to add */	int argcount;		/* number of arguments */	BOOL addrflag;	op = OP_CALL;	index = getbuiltinfunc(name);	if (index < 0) {		op = OP_USERCALL;		index = adduserfunc(name);	}	if (gettoken() == T_RIGHTPAREN) {		if (op == OP_CALL)			builtincheck(index, 0);		addopfunction(op, index, 0);		return;	}	rescantoken();	argcount = 0;	for (;;) {		argcount++;		if (gettoken() == T_RIGHTPAREN) {			addop(OP_UNDEF);			if (op == OP_CALL)				builtincheck(index, argcount);			addopfunction(op, index, argcount);			return;		}		rescantoken();		if (gettoken() == T_COMMA) {			addop(OP_UNDEF);			continue;		}		rescantoken();		addrflag = (gettoken() == T_BACKQUOTE);		if (!addrflag)			rescantoken();		(void) getopassignment();		if (addrflag) {			writeindexop();		}		if (!addrflag && (op != OP_CALL))			addop(OP_GETVALUE);		if (!strcmp(name, "quomod") && argcount > 2)			writeindexop();		switch (gettoken()) {		case T_RIGHTPAREN:			if (op == OP_CALL)				builtincheck(index, argcount);			addopfunction(op, index, argcount);			return;		case T_COMMA:			break;		default:			scanerror(T_SEMICOLON,				  "Missing right parenthesis "				  "in function call");			return;		}	}}/* * Change the current directory.  If no directory is given, assume home. */static voiddo_changedir(void){	char *p;	STRING *s;	/* look at the next token */	(void) tokenmode(TM_NEWLINES | TM_ALLSYMS);	/* determine the new directory */	s = NULL;	switch (gettoken()) {	case T_STRING:		s = findstring(tokenstring());		p = s->s_str;		break;	case T_SYMBOL:		p = tokensymbol();		break;	default:		p = home;	}	if (p == NULL) {		fprintf(stderr, "Cannot determine HOME directory\n");	}	/* change to that directory */	if (chdir(p)) {		perror(p);	}	if (s != NULL)		sfree(s);}

⌨️ 快捷键说明

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