Coder Social home page Coder Social logo

Comments (9)

paladin-t avatar paladin-t commented on May 28, 2024

Hello Julien,

At the very beginning, I didn't add the mb_reset function, it was not able to reset variables at that moment, as you can see, mb_reset was for this purpose. I mean, just call mb_run without reset will re-interprete the script with latest context (variables, scripting interfaces, etc.) properly. Eg.

mb_load_string(bas, "...");
mb_run(bas);
...
mb_run(bas);

Have fun.

Best regards.
WRX.

from my_basic.

paladin-t avatar paladin-t commented on May 28, 2024

Added information in this wiki page.

from my_basic.

julienkrief avatar julienkrief commented on May 28, 2024

Thanks you!

from my_basic.

runvnc avatar runvnc commented on May 28, 2024

Awesome system, thanks. Side question, interested to hear the name of the 8bit/16bit thing you mentioned in another issue, is it on your github already?
OK, so for the question. Quite possible I am missing something, but it seemed as though julienkrief was asking for the same thing I would like, and just not calling mb_reset does not solve it.
I'm trying to make it act as a REPL, so I can type

A$="Hello" '[ENTER]
PRINT A$ '[ENTER]
' "Hello" prints here

So I am calling mb_run every time they press enter. If I keep calling mb_reset, the A$ gets cleared out. If I don't call mb_reset, it acts as if I am trying to run all of the previous statements again, which I'm not -- I just want to run the last statement, but using all of the variables previously defined.

I was sort of able to achieve that, at least for integers being stored, by commenting out a line in mb_reset: //clear_scope_chain(*s) .. and I tested with A=10[ENTER]PRINT A[ENTER] and thought I had succeeded since that worked. But it seems to cause some kind of freeze or crash when I try it with strings, so it must not be that simple. So now I am trying to comment out a bunch of other stuff in mb_reset, but I am kind of blindly hacking at it.

I am guessing either this is something I just can't do, or maybe it is actually sort of simple and you can give me a hint? Thanks for your time.

from my_basic.

runvnc avatar runvnc commented on May 28, 2024

Update: I so far seem to have be able to get a REPL (read-eval-print-loop) just by calling this:

void mb_reset_script(struct mb_interpreter_t** s) {
  _ls_clear((*s)->ast);
}

.. although I have a feeling there are probably some gotchas.

from my_basic.

paladin-t avatar paladin-t commented on May 28, 2024

Hi Jason,

Thank you for your interest. I've made a placeholder repo of project MY-BASIC Builder, but there's nothing make sense yet. I've been developing it during my spare time, quite slowly... It will be a close source freeware, maybe partially open source for a user customizable plugin purpose. My goal is to make it an integrated game/app development software, with retro style (similar to PICO-8, SmileBASIC) and modern BASIC syntax. Since I was expecting to regain retro playing experience with BASIC computers in the past 80/90s with a modern tool.

For your reference, REPL depends on two requirements:

  1. The shell should be able to check whether syntax struct is completely inputted. It should start to interpret line [2]~[4] after line[4] is inputted to finish the loop trunk. Similar processing for other multi-line conditional, routine and class statements. And should be able to process nested syntax structs:
[1] ...
[2] for i = 0 to 10
[3]   ...
[4] next
  1. Call stack should be reenterable. Which means it may pause execution at proper point, then reentry back.

It's possible to make the first point, but it's not able to reentry MY-BASIC's call stack (which are mixed with script frames and native frames). So it's not simple to make it at current version.

However there's a solution, by using system dependent FIBER API, which is implemented and named SwitchToFiber on Windows, and setcontext on POSIX compatible systems.

For instance:

#ifdef MB_COMPACT_MODE
#	pragma pack(1)
#endif /* MB_COMPACT_MODE */

// This struct is copied from `my_basic.c`
// to simply let the shell to tell whether
// it's running to the last line of code.
typedef struct _ls_node_t {
	void* data;
	struct _ls_node_t* prev;
	struct _ls_node_t* next;
	void* extra;
} _ls_node_t;

#ifdef MB_COMPACT_MODE
#	pragma pack()
#endif /* MB_COMPACT_MODE */

// Fiber functions begin.

typedef LPFIBER_START_ROUTINE FiberRoutine;

static void* fiber_create_from_current_thread(void* pars) {
	return ConvertThreadToFiber(pars);
}

static void* fiber_create(size_t stack, FiberRoutine run, void* pars) {
	return CreateFiber(stack, run, pars);
}

static void fiber_delete(void* co) {
	DeleteFiber(co);
}

static void fiber_switch(void* co) {
	SwitchToFiber(co);
}

static void WINAPI fiber_run(void* co) {
	mb_run(bas, false);
}

// Fiber functions end.

static int _on_stepped(struct mb_interpreter_t* s, void** l, char* f, int p, unsigned short row, unsigned short col) {
	_ls_node_t* ast = (_ls_node_t*)*l; // Hack to know interpreter detail.
	if ((ast && !ast->next && row == co_row) || layers != 0) {
		// If it's the last line of code, and there's no incomplete syntax struct,
		// then switch execution control to the main fiber.
		fiber_switch(co_main);
	}

	return MB_FUNC_OK;
}

The main function will be:

int main(int argc, char* argv[]) {
	atexit(_on_exit);

	_on_startup();

	// Creates a main fiber for inputting.
	co_main = fiber_create_from_current_thread(0);

	// Creates another fiber for running.
	void* co_repl = fiber_create(0, fiber_run, 0);

	printf("READY\n");
	do {
		// Gets a line.
		char line[_MAX_LINE_LENGTH];
		memset(line, 0, _MAX_LINE_LENGTH);
		_printf("]");
		mb_gets(line, _MAX_LINE_LENGTH);

		// Checks for commands 
		if (strcmp(line, "bye") == 0) break;

		// Processes syntax structs.
		// TODO : IMPROVE ME!
		if (strstr(line, "for")) ++layers;
		else if (strstr(line, "next")) --layers;

		// Line counting.
		++co_row;

		// Loads a line.
		mb_load_string(bas, line, false);
		mb_load_string(bas, "\n", false);

		// Syntax struct incomplete?
		if (layers > 0)
			continue;

		// Switches to the running fiber.
		fiber_switch(co_repl);
	} while (true);

	// Finishes.
	fiber_delete(co_repl);

	return 0;
}

Tested with input and output:

READY
]a=22
]b=7
]print a/b;
3.14286
]for i=1 to 5
]print i;
]next
1
2
3
4
5
]

I've made some modification at the latest revision to support it.

This code shows how the fiber benefits to make reentry easy, that a developer won't need to write complex code to maintain mixed call stack. However it's still a rough sketch code, you have to identify syntax struct completeness.

FYI. I've implemented coroutine with fiber for MY-BASIC Builder, it will be somehow like this:

' Dispatch manually.
co0 = coroutine(
	lambda () (
		for i in list(1 to 3)
			yield i
		next
		yield lambda () (print "i = " + str(i);)
		yield list()
		return "CO"
	)
)
while move_next(co0)
	t = get(co0)
	if t is type("LIST") then
		print "LIST";
	elseif t is type("ROUTINE") then
		t()
	else
		print t;
	endif
wend

' Dispatch automatically.
co1 = coroutine(
	lambda () (
		for i in list(1 to 3)
			print "1 ", i;
			yield i
		next
	)
)
start_coroutine(co1)

The fiber API depends on specific architecture and OS, so it won't be introduced into the kernel code, coroutine will be for MY-BASIC Builder only.

from my_basic.

runvnc avatar runvnc commented on May 28, 2024

from my_basic.

paladin-t avatar paladin-t commented on May 28, 2024

I just figured out there's another solution without fiber, still need some tricky:

static unsigned short co_row = 0;

static int layers = 0;

#ifdef MB_COMPACT_MODE
#	pragma pack(1)
#endif /* MB_COMPACT_MODE */

typedef struct _ls_node_t {
	void* data;
	struct _ls_node_t* prev;
	struct _ls_node_t* next;
	void* extra;
} _ls_node_t;

#ifdef MB_COMPACT_MODE
#	pragma pack()
#endif /* MB_COMPACT_MODE */

static bool_t _input(void) {
	char line[_MAX_LINE_LENGTH];
	memset(line, 0, _MAX_LINE_LENGTH);
	_printf("]");
	mb_gets(line, _MAX_LINE_LENGTH);
	if (strcmp(line, "bye") == 0) return false;
	if (strstr(line, "for")) ++layers;
	else if (strstr(line, "next")) --layers;
	++co_row;
	mb_load_string(bas, line, false);
	mb_load_string(bas, "\n", false);

	return true;
}

static int _on_stepped(struct mb_interpreter_t* s, void** l, char* f, int p, unsigned short row, unsigned short col) {
	_ls_node_t* ast = (_ls_node_t*)*l;
	if ((ast && !ast->next && row == co_row) || layers != 0) {
		do {
			if (!_input())
				return MB_FUNC_BYE;
		} while (layers > 0);
	}

	return MB_FUNC_OK;
}

int main(int argc, char* argv[]) {
	atexit(_on_exit);

	_on_startup();

	printf("READY\n");
	do {
		if (!_input()) break;
		if (layers > 0)
			continue;
		if (mb_run(bas, false) != MB_FUNC_OK)
			break;
	} while (true);

	return 0;
}

I'd rethink it carefully about reenterable and many other details if I had a chance to re-implement it, perhaps rewrite the kernel as v2.0 someday :S

from my_basic.

runvnc avatar runvnc commented on May 28, 2024

Thanks, this helped so much!

from my_basic.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.