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

📄 codegen.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * Copyright (c) 1994 David I. Bell * Permission is granted to use, distribute, or modify this source, * provided that this copyright notice remains intact. * * Module to generate opcodes from the input tokens. */#include "calc.h"#include "token.h"#include "symbol.h"#include "label.h"#include "opcodes.h"#include "string.h"#include "func.h"#include "config.h"static BOOL rdonce;	/* TRUE => do not reread this file */FUNC *curfunc;static BOOL getfilename(), getid();static void getshowcommand(), getfunction(), getbody(), getdeclarations();static void getstatement(), getobjdeclaration(), getobjvars();static void getmatdeclaration(), getsimplebody(), getonedeclaration();static void getcondition(), getmatargs(), getelement(), usesymbol();static void definesymbol(), getcallargs();static int getexprlist(), getassignment(), getaltcond(), getorcond();static int getandcond(), getrelation(), getsum(), getproduct();static int getorexpr(), getandexpr(), getshiftexpr(), getterm();static int getidexpr();static long getinitlist();/* * 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(toplevel)	BOOL toplevel;{	char name[PATHSIZE+1];	/* program name */	if (!toplevel)		enterfilescope();	for (;;) {		(void) tokenmode(TM_NEWLINES);		switch (gettoken()) {		case T_DEFINE:			getfunction();			break;		case T_EOF:			if (!toplevel)				exitfilescope();			return;		case T_HELP:			if (!getfilename(name, FALSE, NULL)) {				strcpy(name, DEFAULTCALCHELP);			}			givehelp(name);			break;		case T_READ:			if (!getfilename(name, TRUE, &rdonce))				break;			switch (opensearchfile(name,calcpath,CALCEXT,rdonce)) {			case 0:				getcommands(FALSE);				break;			case 1:				/* previously read and -once was given */				break;			default:				scanerror(T_NULL, "Cannot open \"%s\"\n", name);				break;			}			break;		case T_WRITE:			if (!getfilename(name, TRUE, NULL))				break;			if (writeglobals(name))				scanerror(T_NULL, "Error writing \"%s\"\n", name);			break;		case T_SHOW:			rescantoken();			getshowcommand();			break;		case T_NEWLINE:		case T_SEMICOLON:			break;		default:			rescantoken();			initstack();			if (evaluate(FALSE))				updateoldvalue(curfunc);		}	}}/* * 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. */BOOLevaluate(nestflag)	BOOL nestflag;		/* TRUE if this is a nested evaluation */{	char *funcname;	BOOL gotstatement;	funcname = (nestflag ? "**" : "*");	beginfunc(funcname, nestflag);	gotstatement = FALSE;	for (;;) {		switch (gettoken()) {			case T_SEMICOLON:				break;			case T_NEWLINE:			case T_EOF:				goto done;			case T_GLOBAL:			case T_LOCAL:			case T_STATIC:				if (gotstatement) {					scanerror(T_SEMICOLON, "Declarations must be used before code");					return FALSE;				}				rescantoken();				getdeclarations();				break;			default:				rescantoken();				getstatement(NULL_LABEL, NULL_LABEL,					NULL_LABEL, NULL_LABEL);				gotstatement = TRUE;		}	}done:	addop(OP_UNDEF);	addop(OP_RETURN);	checklabels();	if (errorcount)		return FALSE;	calculate(curfunc, 0);	return TRUE;}/* * Get a function declaration. * func = name '(' '' | name [ ',' name] ... ')' simplebody *	| name '(' '' | name [ ',' name] ... ')' body. */static voidgetfunction(){	char *name;		/* parameter name */	int type;		/* type of token read */	(void) tokenmode(TM_DEFAULT);	if (gettoken() != T_SYMBOL) {		scanerror(T_NULL, "Function name expected");		return;	}	beginfunc(tokenstring(), FALSE);	enterfuncscope();	if (gettoken() != T_LEFTPAREN) {		scanerror(T_SEMICOLON, "Left parenthesis expected for function");		return;	}	for (;;) {		type = gettoken();		if (type == T_RIGHTPAREN)			break;		if (type != T_SYMBOL) {			scanerror(T_COMMA, "Bad function definition");			return;		}		name = tokenstring();		switch (symboltype(name)) {			case SYM_UNDEFINED:			case SYM_GLOBAL:			case SYM_STATIC:				(void) addparam(name);				break;			default:				scanerror(T_NULL, "Parameter \"%s\" is already defined", name);		}		type = gettoken();		if (type == T_RIGHTPAREN)			break;		if (type != T_COMMA) {			scanerror(T_COMMA, "Bad function definition");			return;		}	}	switch (gettoken()) {		case T_ASSIGN:			rescantoken();			getsimplebody();			break;		case T_LEFTBRACE:			rescantoken();			getbody(NULL_LABEL, NULL_LABEL, NULL_LABEL,				NULL_LABEL, TRUE);			break;		default:			scanerror(T_NULL,				"Left brace or equals sign expected for function");			return;	}	addop(OP_UNDEF);	addop(OP_RETURN);	endfunc();	exitfuncscope();}/* * Get a simple assignment style body for a function declaration. * simplebody = '=' assignment '\n'. */static voidgetsimplebody(){	if (gettoken() != T_ASSIGN) {		scanerror(T_SEMICOLON, "Missing equals for simple function body");		return;	}	(void) tokenmode(TM_NEWLINES);	(void) getexprlist();	addop(OP_RETURN);	if (gettoken() != T_SEMICOLON)		rescantoken();	if (gettoken() != T_NEWLINE)		scanerror(T_NULL, "Illegal function definition");}/* * Get the body of a function, or a subbody of a function. * body = '{' [ declarations ] ... [ statement ] ... '}' *	| [ declarations ] ... [statement ] ... '\n' */static voidgetbody(contlabel, breaklabel, nextcaselabel, defaultlabel, toplevel)	LABEL *contlabel, *breaklabel, *nextcaselabel, *defaultlabel;	BOOL toplevel;{	BOOL gotstatement;	/* TRUE if seen a real statement yet */	int oldmode;	if (gettoken() != T_LEFTBRACE) {		scanerror(T_SEMICOLON, "Missing left brace for function body");		return;	}	oldmode = tokenmode(TM_DEFAULT);	gotstatement = FALSE;	while (TRUE) {		switch (gettoken()) {		case T_RIGHTBRACE:			(void) tokenmode(oldmode);			return;		case T_GLOBAL:		case T_LOCAL:		case T_STATIC:			if (!toplevel) {				scanerror(T_SEMICOLON, "Declarations must be at the top of the function");				return;			}			if (gotstatement) {				scanerror(T_SEMICOLON, "Declarations must be used before code");				return;			}			rescantoken();			getdeclarations();			break;		default:			rescantoken();			getstatement(contlabel, breaklabel, nextcaselabel, defaultlabel);			gotstatement = TRUE;		}	}}/* * Get a line of possible local, global, or static variable declarations. * declarations = { LOCAL | GLOBAL | STATIC } onedeclaration *	[ ',' onedeclaration ] ... ';'. */static voidgetdeclarations(){	int type;	type = gettoken();	if ((type != T_LOCAL) && (type != T_GLOBAL) && (type != T_STATIC)) {		rescantoken();		return;	}	while (TRUE) {		getonedeclaration(type);		switch (gettoken()) {			case T_COMMA:				continue;			case T_NEWLINE:			case T_SEMICOLON:				return;			default:				scanerror(T_SEMICOLON, "Bad syntax in declaration statement");				return;		}	}}/* * Get a single declaration of a symbol of the specified type. * onedeclaration = name [ '=' getassignment ] *	| 'obj' type name [ '=' objvalues ] *	| 'mat' name '[' matargs ']' [ '=' matvalues ]. */static voidgetonedeclaration(type)	int type;{	char *name;		/* name of symbol seen */	int symtype;		/* type of symbol */	int vartype;		/* type of variable being defined */	LABEL label;	switch (type) {		case T_LOCAL:			symtype = SYM_LOCAL;			break;		case T_GLOBAL:			symtype = SYM_GLOBAL;			break;		case T_STATIC:			symtype = SYM_STATIC;			clearlabel(&label);			addoplabel(OP_INITSTATIC, &label);			break;		default:			symtype = SYM_UNDEFINED;			break;	}	vartype = gettoken();	switch (vartype) {		case T_SYMBOL:			name = tokenstring();			definesymbol(name, symtype);			break;		case T_MAT:			addopone(OP_DEBUG, linenumber());			getmatdeclaration(symtype);			if (symtype == SYM_STATIC)				setlabel(&label);			return;		case T_OBJ:			addopone(OP_DEBUG, linenumber());			getobjdeclaration(symtype);			if (symtype == SYM_STATIC)				setlabel(&label);			return;		default:			scanerror(T_COMMA, "Bad syntax for declaration");			return;	}	if (gettoken() != T_ASSIGN) {		rescantoken();		if (symtype == SYM_STATIC)			setlabel(&label);		return;	}	/*	 * Initialize the variable with the expression.  If the variable is	 * static, arrange for the initialization to only be done once.	 */	addopone(OP_DEBUG, linenumber());	usesymbol(name, FALSE);	getassignment();	addop(OP_ASSIGNPOP);	if (symtype == SYM_STATIC)		setlabel(&label);}/* * 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 ';' *	| MAT name '[' value [ ':' value ] [',' value [ ':' value ] ] ']' ';' *	| OBJ type '{' arg [ ',' arg ] ... '}' ] ';' *	| OBJ type name [ ',' name ] ';' *	| PRINT assignment [, assignment ] ... ';' *	| QUIT [ string ] ';' *	| SHOW item ';' *	| body *	| assignment ';' *	| label ':' statement *	| ';'. */static voidgetstatement(contlabel, breaklabel, nextcaselabel, defaultlabel)	LABEL *contlabel;	/* label for continue statement */	LABEL *breaklabel;	/* label for break statement */	LABEL *nextcaselabel;	/* label for next case statement */	LABEL *defaultlabel;	/* label for default case */{	LABEL label1, label2, label3, label4;	/* locations for jumps */	int type;	BOOL printeol;	addopone(OP_DEBUG, linenumber());	switch (gettoken()) {	case T_NEWLINE:	case T_SEMICOLON:		return;	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(tokenstring());		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:		rescantoken();		getbody(contlabel, breaklabel, nextcaselabel, defaultlabel, FALSE);		return;	case T_IF:		clearlabel(&label1);		clearlabel(&label2);		getcondition();		addoplabel(OP_JUMPEQ, &label1);		getstatement(contlabel, breaklabel, NULL_LABEL, NULL_LABEL);		if (gettoken() != T_ELSE) {			setlabel(&label1);			rescantoken();			return;		}		addoplabel(OP_JUMP, &label2);		setlabel(&label1);		getstatement(contlabel, breaklabel, NULL_LABEL, NULL_LABEL);		setlabel(&label2);		return;	case T_FOR:	/* for (a; b; c) x */		clearlabel(&label1);		clearlabel(&label2);		clearlabel(&label3);		clearlabel(&label4);		contlabel = NULL_LABEL;		breaklabel = &label4;		if (gettoken() != T_LEFTPAREN) {			scanerror(T_SEMICOLON, "Left parenthesis expected");			return;		}		if (gettoken() != T_SEMICOLON) {	/* have 'a' part */			rescantoken();			(void) getexprlist();			addop(OP_POP);			if (gettoken() != T_SEMICOLON) {				scanerror(T_SEMICOLON, "Missing semicolon");				return;			}		}		if (gettoken() != T_SEMICOLON) {	/* have 'b' part */			setlabel(&label1);			contlabel = &label1;			rescantoken();			(void) getexprlist();			addoplabel(OP_JUMPNE, &label3);			addoplabel(OP_JUMP, breaklabel);			if (gettoken() != T_SEMICOLON) {				scanerror(T_SEMICOLON, "Missing semicolon");				return;			}		}		if (gettoken() != T_RIGHTPAREN) {	/* have 'c' part */			if (label1.l_offset <= 0)				addoplabel(OP_JUMP, &label3);			setlabel(&label2);			contlabel = &label2;			rescantoken();			(void) getexprlist();			addop(OP_POP);			if (label1.l_offset > 0)				addoplabel(OP_JUMP, &label1);			if (gettoken() != T_RIGHTPAREN) {				scanerror(T_SEMICOLON, "Right parenthesis expected");				return;			}		}		setlabel(&label3);		if (contlabel == NULL_LABEL)			contlabel = &label3;		getstatement(contlabel, breaklabel, NULL_LABEL, NULL_LABEL);		addoplabel(OP_JUMP, contlabel);		setlabel(breaklabel);		return;	case T_WHILE:		contlabel = &label1;		breaklabel = &label2;		clearlabel(contlabel);		clearlabel(breaklabel);		setlabel(contlabel);		getcondition();		addoplabel(OP_JUMPEQ, breaklabel);		getstatement(contlabel, breaklabel, NULL_LABEL, NULL_LABEL);		addoplabel(OP_JUMP, contlabel);		setlabel(breaklabel);		return;	case T_DO:		contlabel = &label1;		breaklabel = &label2;		clearlabel(contlabel);		clearlabel(breaklabel);		clearlabel(&label3);		setlabel(&label3);		getstatement(contlabel, breaklabel, NULL_LABEL, NULL_LABEL);		if (gettoken() != T_WHILE) {			scanerror(T_SEMICOLON, "WHILE keyword expected for DO statement");			return;		}		setlabel(contlabel);		getcondition();		addoplabel(OP_JUMPNE, &label3);		setlabel(breaklabel);		return;	case T_SWITCH:		breaklabel = &label1;		nextcaselabel = &label2;		defaultlabel = &label3;		clearlabel(breaklabel);		clearlabel(nextcaselabel);		clearlabel(defaultlabel);		getcondition();		if (gettoken() != T_LEFTBRACE) {			scanerror(T_SEMICOLON, "Missing left brace for switch statement");			return;		}		addoplabel(OP_JUMP, nextcaselabel);		rescantoken();		getstatement(contlabel, breaklabel, nextcaselabel, defaultlabel);		addoplabel(OP_JUMP, breaklabel);		setlabel(nextcaselabel);		if (defaultlabel->l_offset > 0)			addoplabel(OP_JUMP, defaultlabel);		else			addop(OP_POP);		setlabel(breaklabel);		return;	case T_CASE:		if (nextcaselabel == NULL_LABEL) {			scanerror(T_SEMICOLON, "CASE not within SWITCH statement");			return;		}

⌨️ 快捷键说明

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