Example #1
0
/////////
//
//	Parse and interpret a stream, and return its value
//
//	This is used in doCommand to execute a passed-in or collected text command,
// in domacrocommand() when a macro/function is called from within a parse stream,
//	and in runBackgroundTasks to kick off the background run.
//
//
numvar execscript(byte scripttype, numvar scriptaddress, char *scriptname) {

	// save parse context
	parsepoint fetchmark;
	markparsepoint(&fetchmark);
	byte thesym = sym;
	vpush(symval);

	// if this is the first stream context in this invocation,
	// set up our error recovery point and init the value stack
	// otherwise we skip this to allow nested execution calls 
	// to properly return to top
	//
	if (fetchtype == SCRIPT_NONE) {

		// Exceptions come here via longjmp; see bitlash-error.c
		switch(setjmp(env)) {
			case 0: break;
			case X_EXIT: {

				// POLICY: Stop all background tasks on any error
				//
				// It is not possible to be certain that continuing here will work.
				// Not all errors leave the interpreter in a working state.  Though most do.
				// The conservative/deterministic choice is to stop all background tasks
				// and drop the user back to the command prompt.
				//
				// On the other hand, you may find this inconvenient in your application, 
				// and may be happy taking the risk of continuing.
				//
				// In which case, comment out this line and proceed with caution.
				//	
				// TODO: if the macro "onerror" exists, call it here instead.  Let it "stop *".
				//
				// -br
				//
				initTaskList();		// stop all pending tasks

#ifdef SOFTWARE_SERIAL_TX
				resetOutput();		// clean up print module
#endif
				// Other cleanups here
				vinit();			// initialize the expression stack
				fetchtype = SCRIPT_NONE;	// reset parse context
				fetchptr = 0L;				// reset parse location
				// sd_up = 0;				// TODO: reset file system
				return (numvar) -1;
			}							// X_EXIT case
		}								// switch
	}
	initparsepoint(scripttype, scriptaddress, scriptname);
	getsym();

	// interpret the function text and collect its result
	numvar ret = getstatementlist();
	returntoparsepoint(&fetchmark, 1);		// now where were we?
	sym = thesym;
	symval = vpop();
	return ret;
}
/////////
//
//	"cat": copy file to serial out
//
numvar sdcat(void) {
	if (!scriptfileexists((char *) getarg(1))) return 0;
	numvar fetchmark = markparsepoint();
	initparsepoint(SCRIPT_FILE, 0L, (char *) getarg(1));
	while (inchar) {
		if (inchar == '\n') spb('\r');
		spb(inchar);
		fetchc();
	}
	returntoparsepoint(fetchmark, 1);
	return 1;
}
//////////
//
//	func_fprintf(): implementation of fprintf() function
//
//
numvar func_fprintf(void) {
	numvar fetchmark = markparsepoint();

	scriptwrite((char *) getarg(1), "", 1);		// open the file for append (but append nothing)

	//serialOutputFunc saved_handler = serial_override_handler;	// save previous output handler
	setOutputHandler(scriptwritebyte);			// set file output handler

	func_printf_handler(2,3);	// format=arg(2), optional args start at 3

	//setOutputHandler(saved_handler);// restore output handler
	resetOutputHandler();
	returntoparsepoint(fetchmark, 1);
}
Example #4
0
/////////
//
//	sdwrite: write or append a line to a file
//
numvar sdwrite(char *filename, char *contents, byte append) {
#if !defined(UNIX_BUILD)
	parsepoint fetchmark;
	markparsepoint(&fetchmark);
#endif

	if (!scriptwrite(filename, contents, append)) unexpected(M_oops);

#if !defined(UNIX_BUILD)
	returntoparsepoint(&fetchmark, 1);
#endif

	return 1;
}
// The switch statement: execute one of N statements based on a selector value
// switch <numval> { stmt0; stmt1;...;stmtN }
// numval < 0: treated as numval == 0
// numval > N: treated as numval == N
//
numvar getswitchstatement(void) {
numvar thesymval = symval;
//char *fetchmark;
numvar fetchmark;
numvar retval = 0;
byte thesym = sym;

	getsym();						// eat "switch"
	getnum();						// evaluate the switch selector
	if (expval < 0) expval = 0;		// map negative values to zero
	byte which = (byte) expval;		// and stash it for reference
	if (sym != s_lcurly) expectedchar('{');
	getsym();		// eat "{"

	// we sit before the first statement
	// scan and discard the <selector>'s worth of statements 
	// that sit before the one we want
	while ((which > 0) && (sym != s_eof) && (sym != s_rcurly)) {
		//fetchmark = fetchptr;
		fetchmark = markparsepoint();
		thesym = sym;
		thesymval = symval;
		skipstatement();
		if ((sym != s_eof) && (sym != s_rcurly)) --which;
	}

	// If the selector is greater than the number of statements,
	// back up and execute the last one
	if (which > 0) {					// oops ran out of piddys
		//fetchptr = fetchmark;			// restore to last statement
		//primec();						// set up for getsym()
		returntoparsepoint(fetchmark, 0);
		sym = thesym;
		symval = thesymval;
	}
	//unexpected(M_number);

	// execute the statement we're pointing at
	retval = getstatement();

	// eat the rest of the statement block to "}"
	while ((sym != s_eof) && (sym != s_rcurly)) skipstatement();
	if (sym == s_rcurly) getsym();		// eat "}"
	return retval;
}
Example #6
0
//////////
//
//	func_fprintf(): implementation of fprintf() function
//
//
numvar func_fprintf(void) {
	parsepoint fetchmark;
	markparsepoint(&fetchmark);

	scriptwrite((char *) getarg(1), "", 1);		// open the file for append (but append nothing)

	//serialOutputFunc saved_handler = serial_override_handler;	// save previous output handler
	void scriptwritebyte(byte);
	setOutputHandler(scriptwritebyte);			// set file output handler

	func_printf_handler(2,3);	// format=arg(2), optional args start at 3

	//setOutputHandler(saved_handler);// restore output handler
	resetOutputHandler();
#ifdef scriptclose
    scriptclose();          // close and flush the output
#endif
	returntoparsepoint(&fetchmark, 1);
}
// Get a statement
numvar getstatement(void) {
numvar retval = 0;
//char *fetchmark;
numvar fetchmark;

	chkbreak();

	if (sym == s_while) {
		// at this point sym is pointing at s_while, before the conditional expression
		// save fetchptr so we can restart parsing from here as the while iterates
		//fetchmark = fetchptr;
		fetchmark = markparsepoint();
		for (;;) {
			//fetchptr = fetchmark;			// restore to mark
			//primec();						// set up for mr. getsym()
			returntoparsepoint(fetchmark, 0);
			getsym(); 						// fetch the start of the conditional
			if (getnum()) {
				retval = getstatement();
				if (sym == s_returning) break;	// exit if we caught a return
			}
			else {
				skipstatement();
				break;
			}
		}
	}
	
	else if (sym == s_if) {
		getsym();			// eat "if"
		if (getnum()) {
			retval = getstatement();
			if (sym == s_else) {
				getsym();	// eat "else"
				skipstatement();
			}
		} else {
			skipstatement();
			if (sym == s_else) {
				getsym();	// eat "else"
				retval = getstatement();
			}
		}
	}
	else if (sym == s_lcurly) {
		getsym(); 	// eat "{"
		while ((sym != s_eof) && (sym != s_returning) && (sym != s_rcurly)) retval = getstatement();
		if (sym == s_rcurly) getsym();	// eat "}"
	}
	else if (sym == s_return) {
		getsym();	// eat "return"
		if ((sym != s_eof) && (sym != s_semi)) retval = getnum();
		sym = s_returning;		// signal we're returning up the line
	}
	else if (sym == s_switch) retval = getswitchstatement();

	else if (sym == s_function) cmd_function();

	else if (sym == s_run) {	// run macroname
		getsym();
		if ((sym != s_script_eeprom) && (sym != s_script_progmem) &&
			(sym != s_script_file)) unexpected(M_id);

		// address of macroid is in symval via parseid
		// check for [,snoozeintervalms]
		getsym();	// eat macroid to check for comma; symval untouched
		if (sym == s_comma) {
			vpush(symval);
			getsym();			// eat the comma
			getnum();			// get a number or else
			startTask(vpop(), expval);
		}
		else startTask(symval, 0);
	}

	else if (sym == s_stop) {
		getsym();
		if (sym == s_mul) {						// stop * stops all tasks
			initTaskList();
			getsym();
		}
		else if ((sym == s_semi) || (sym == s_eof)) {
			if (background) stopTask(curtask);	// stop with no args stops the current task IF we're in back
			else initTaskList();				// in foreground, stop all
		}
		else stopTask(getnum());
	}

	else if (sym == s_boot) reboot();
	else if (sym == s_rm) {		// rm "sym" or rm *
		getsym();
		if (sym == s_script_eeprom) {
			eraseentry(idbuf);
		} 
		else if (sym == s_mul) nukeeeprom();
		else if (sym != s_undef) expected(M_id);
		getsym();
	}
	else if (sym == s_ps) 		{ getsym();	showTaskList(); }
	else if (sym == s_peep) 	{ getsym(); cmd_peep(); }
	else if (sym == s_ls) 		{ getsym(); cmd_ls(); }
	else if (sym == s_help) 	{ getsym(); cmd_help(); }
	else if (sym == s_print) 	{ getsym(); cmd_print(); }
	else if (sym == s_semi)		{ ; }	// ;)

#ifdef HEX_UPLOAD
	// a line beginning with a colon is treated as a hex record
	// containing data to upload to eeprom
	//
	// TODO: verify checksum
	//
	else if (sym == s_colon) {
		// fetchptr points at the byte count
		byte byteCount = gethex(2);		// 2 bytes byte count
		int addr = gethex(4);			// 4 bytes address
		byte recordType = gethex(2);	// 2 bytes record type; now fetchptr -> data
		if (recordType == 1) reboot();	// reboot on EOF record (01)
		if (recordType != 0) return;	// we only handle the data record (00)
		if (addr == 0) nukeeeprom();	// auto-clear eeprom on write to 0000
		while (byteCount--) eewrite(addr++, gethex(2));		// update the eeprom
		gethex(2);						// discard the checksum
		getsym();						// and re-prime the parser
	}
#endif

	else getexpression();

	if (sym == s_semi) getsym();		// eat trailing ';'
	return retval;
}
/////////
//
//	sdwrite: write or append a line to a file
//
numvar sdwrite(char *filename, char *contents, byte append) {
	numvar fetchmark = markparsepoint();
	if (!scriptwrite(filename, contents, append)) unexpected(M_oops);
	returntoparsepoint(fetchmark, 1);
	return 1;
}