コード例 #1
0
ファイル: bitlash-eeprom.c プロジェクト: GIRA/Physical-Etoys
// write id:value, unless value is empty, in which case we erase the id
void writeMacro(char *id) {
	eraseentry(id);

	// we need to know the macro value length to allocate space for it
	// we don't realistically have enough buffer space handy to parse it into
	// so this is a two-pass operation: first we measure the text, then on
	// the second pass we stuff it into the eeprom
	//
	// measure length of macro value
	// we get here with inchar = first char of macro and fetchptr one past that
	//
	char *fetchmark = --fetchptr;		// back up and mark first char of macro text
	primec();							// re-prime
	expval = 0;							// zero the count
	parsestring(&countByte);			// now expval is the macro value length
	if (!expval) return;				// empty string? we're done
	
	int addr = findhole(strlen(id) + expval + 2);	// longjmps on fail
	if (addr >= 0) {
		saveString(addr, id);

		// reset parse context
		fetchptr = fetchmark;
		primec();

		expval = addr + strlen(id) + 1;		// set up address for saveByte
		parsestring(&saveByte);
		saveByte(0);
	}
}
コード例 #2
0
void initparsepoint(byte scripttype, numvar scriptaddress, char *scriptname) {

#ifdef PARSER_TRACE
	if (trace) {
		speol();
		sp("init:");printHex(scripttype); spb(' '); printHex(scriptaddress); 
		if (scriptname) { spb(' '); sp(scriptname); }
		speol();
	}
#endif

	fetchtype = scripttype;
	fetchptr = scriptaddress;
	
	// if we're restoring to idle, we're done
	if (fetchtype == SCRIPT_NONE) return;

#if defined(SDFILE)
	// handle file transition side effects here, once per transition,
	// rather than once per character below in primec()
	if (fetchtype == SCRIPT_FILE) {

		// ask the file glue to open and position the file for us
		if (!scriptopen(scriptname, scriptaddress, O_READ)) unexpected(M_oops);		// TODO: error message
	}
#endif

	primec();	// re-fetch inchar
}
コード例 #3
0
/////////
//
//	fetchc(): 
//		advance input to next character of input stream
//		and set inchar to the character found there
//
void fetchc(void) {
	++fetchptr;

#ifdef PARSER_TRACE
	if (trace) {
		spb('[');
		printHex(fetchptr);
		spb(']');
	}
#endif

	primec();
}
コード例 #4
0
void doMacroCall(int macroaddress) {
char op = sym;					// save sym for restore
	if (macroaddress >= 0) {
	
		char *fetchmark = fetchptr;			// save the current parse pointer
	
		// call the macro
		calleeprommacro(findend(macroaddress));	// register the macro into the parser stream
		getsym();
		getstatementlist();		// parse and execute the macro code here
		if (sym != s_eof) expected(M_eof);
	
		// restore parsing context so we can resume cleanly
		fetchptr = fetchmark;	// restore pointer
		primec();				// and inchar
		sym = op;				// restore saved sym
	}
}
コード例 #5
0
// 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 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;
		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()
		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;
}
コード例 #6
0
// call a macro and push its return value on the stack
//
void domacrocall(int macroaddress) {
	if (macroaddress >= 0) {
	
		parsearglist();
		byte thesym = sym;					// save sym for restore
		vpush(symval);						// and symval
		char *fetchmark = fetchptr;			// save the current parse pointer

		// call the macro
		calleeprommacro(findend(macroaddress));	// register the macro into the parser stream
		getsym();								// fetch its first symbol
		
		numvar ret = getstatementlist();		// parse and execute the macro code here
//		if (sym != s_eof) expected(M_eof);

		// restore parsing context so we can resume cleanly
		symval = vpop();		// restore symval
		sym = thesym;			// restore saved sym
		releaseargblock();		// drop the args
		fetchptr = fetchmark;	// restore pointer
		primec();				// and inchar
		vpush(ret);				// send back our return value
	}
}
コード例 #7
0
// Get a statement
void getstatement(void) {

#if !defined(TINY85)
	chkbreak();
#endif

	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
		char *fetchmark = fetchptr;
		for (;;) {
			fetchptr = fetchmark;			// restore to mark
			primec();						// set up for mr. getsym()
			getsym(); 						// fetch the start of the conditional
			if (!getnum()) {					
				//longjmp(env, X_EXIT);		// get the conditional; exit on false
				sym = s_eof;				// we're finished here.  move along.
				return;
			}
			if (sym != s_colon) expectedchar(':');
			getsym();	// eat :
			getstatementlist();
		}
	}
	
	else if (sym == s_if) {
		getsym(); 								// fetch the start of the conditional
		if (!getnum()) {
			//longjmp(env, X_EXIT);	// get the conditional; exit on false
			sym = s_eof;
			return;
		}
		if (sym != s_colon) expectedchar(':');
		getsym();	// eat :
		getstatementlist();
	}


#if SKETCH
	// The switch statement: call one of N macros based on a selector value
	// switch <numval>: macroid1, macroid2,.., macroidN
	// numval < 0: numval = 0
	// numval > N: numval = N

	else if (sym == s_switch) {
		getsym();	// eat "switch"
		numvar selector = getnum();	// evaluate the switch value
		if (selector < 0) selector = 0;
		if (sym != s_colon) expectedchar(':');

		// we sit before the first macroid
		// scan and discard the <selector>'s worth of macro ids 
		// that sit before the one we want
		for (;;) {
			getsym();	// get an id, sets symval to its eeprom addr as a side effect
			if (sym != s_macro) expected (6);		// TODO: define M_macro instead of 6
			getsym();	// eat id, get separator; assume symval is untouched
			if ((sym == s_semi) || (sym == s_eof)) break;	// last case is default so we exit always
			if (sym != s_comma) expectedchar(',');
			if (!selector) break;		// ok, this is the one we want to execute
			selector--;					// one down...
		}

		// call the macro whose addr is squirreled in symval all this time
		// on return, the parser is ready to pick up where we left off
		doMacroCall(symval);

		// scan past the rest of the unused switch options, if any
		// TODO: syntax checking for non-chosen options could be made much tighter at the cost of some space
		while ((sym != s_semi) && (sym != s_eof)) getsym();		// scan to end of statement without executing
	}
#endif


	else if ((sym == s_macro) || (sym == s_undef)) {		// macro def or ref
		getsym();						// scan past macro name to next symbol: ; or :=
		if (sym == s_define) {			// macro definition: macroid := strvalue
			// to define the macro, we need to copy the id somewhere on the stack
			// to avoid having this local buffer in every getstatement stack frame,
			// we break out defineMacro here to a separate function that only eats that
			// stack in the case that a macro is being defined
#ifdef TINY85
			unexpected(M_defmacro);
#else
			defineMacro();
#endif
		}
		else if ((sym == s_semi) || (sym == s_eof)) {	// valid macro reference: let's call it
#if SKETCH
			doMacroCall(symval);			// parseid stashes the macro address in symval
#else
			char op = sym;					// save sym for restore
			expval = findKey(idbuf);		// assumes id in idbuf isn't clobbered since getsym() above
			if (expval >= 0) {
				char *fetchmark = fetchptr;			// save the current parse pointer

				// call the macro
				calleeprommacro(findend(expval));	// register the macro into the parser stream
				getsym();
				getstatementlist();		// parse and execute the macro code here
				if (sym != s_eof) expected(M_eof);

				// restore parsing context so we can resume cleanly
				fetchptr = fetchmark;	// restore pointer
				primec();				// and inchar
				sym = op;				// restore saved sym: s_semi or s_eof
			} else unexpected(M_id);
#endif
		}
		else expectedchar(';');
		//else getexpression();		// assume it was macro1+32+macro2...
	}
	
	else if (sym == s_run) {	// run macroname
		getsym();
		if (sym != s_macro) unexpected(M_id);

#if 0
		// address of macroid is in symval via parseid
		startTask(kludge(symval));
		getsym();
#else
		// 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(kludge(vpop()), expval);
		}
		else startTask(kludge(symval), 0);
#endif
	}
	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();

#if !defined(TINY85)
	else if (sym == s_rm) {		// rm "sym" or rm *
		getsym();
		if (sym == s_macro) {
			eraseentry(idbuf);
		} 
		else if (sym == s_mul) nukeeeprom();
		else expected(M_id);
		getsym();
	}
	else if (sym == s_ps) 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(); }
#endif

#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();
	}
}
コード例 #8
0
// Get a statement
numvar getstatement(void) {
numvar retval = 0;
char *fetchmark;

	chkbreak();

//#define LINEMODE
#ifdef LINEMODE
	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
		char *fetchmark = fetchptr;
		for (;;) {
			fetchptr = fetchmark;			// restore to mark
			primec();						// set up for mr. getsym()
			getsym(); 						// fetch the start of the conditional
			if (!getnum()) {					
				//longjmp(env, X_EXIT);		// get the conditional; exit on false
				sym = s_eof;				// we're finished here.  move along.
				return;
			}
			if (sym != s_colon) expectedchar(':');
			getsym();	// eat :
			getstatementlist();
		}
	}
	else if (sym == s_if) {
		getsym(); 								// fetch the start of the conditional
		if (!getnum()) {
			//longjmp(env, X_EXIT);	// get the conditional; exit on false
			sym = s_eof;
			return;
		}
		if (sym != s_colon) expectedchar(':');
		getsym();	// eat :
		getstatementlist();
	}

	// The switch statement: call one of N macros based on a selector value
	// switch <numval>: macroid1, macroid2,.., macroidN
	// numval < 0: numval = 0
	// numval > N: numval = N

	else if (sym == s_switch) {
		getsym();	// eat "switch"
		numvar selector = getnum();	// evaluate the switch value
		if (selector < 0) selector = 0;
		if (sym != s_colon) expectedchar(':');

		// we sit before the first macroid
		// scan and discard the <selector>'s worth of macro ids 
		// that sit before the one we want
		for (;;) {
			getsym();	// get an id, sets symval to its eeprom addr as a side effect
			if (sym != s_macro) expected (6);		// TODO: define M_macro instead of 6
			getsym();	// eat id, get separator; assume symval is untouched
			if ((sym == s_semi) || (sym == s_eof)) break;	// last case is default so we exit always
			if (sym != s_comma) expectedchar(',');
			if (!selector) break;		// ok, this is the one we want to execute
			selector--;					// one down...
		}

		// call the macro whose addr is squirreled in symval all this time
		// on return, the parser is ready to pick up where we left off
		domacrocall(symval);

		// scan past the rest of the unused switch options, if any
		// TODO: syntax checking for non-chosen options could be made much tighter at the cost of some space
		while ((sym != s_semi) && (sym != s_eof)) getsym();		// scan to end of statement without executing
	}

#else
	// new statement handling
	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;
		for (;;) {
			fetchptr = fetchmark;			// restore to mark
			primec();						// set up for mr. getsym()
			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();

#endif


	else if (sym == s_run) {	// run macroname
		getsym();
		if (sym != s_macro) 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(kludge(vpop()), expval);
		}
		else startTask(kludge(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();

#if !defined(TINY85)
	else if (sym == s_rm) {		// rm "sym" or rm *
		getsym();
		if (sym == s_macro) {
			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)		{ ; }	// ;)
#endif

#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;
}
コード例 #9
0
// call macro in eeprom
void calleeprommacro(int macrotext) {
	// terrible horrible eeprom kludge
	//callmacro(kludge(macrotext));
	fetchptr = kludge(macrotext);
	primec();
}