Talk:Higher Subleq

Esoteric?
Is this an esoteric language?--TehZ 20:32, 25 December 2010 (UTC)
 * Probably; even if it isn't, it is on-topic, as it is intended to compile to Subleq, which is definitely esoteric. —ehird 20:59, 25 December 2010 (UTC)

Accessing internal registers
I've found that although the  (stack top pointer),   (stack frame base pointer),   (local return address), and   (most recent return value) variables aren't directly accessible to the programmer, it's possible to read them and write to them by calling a function and accessing or altering the stack frame. Some C functions that require the use of internal registers are,  , and. I wrote getter/setter functions for all of the registers as well as working,  , and   functions. These require no modifications to the compiler and seem to work correctly even in complex situations. They sometimes require a few static variables, which begin with a single underscore followed by the function name without any leading underscores. These static variables are so the functions can store data without using stack-relative local variables or arguments, which will become inaccessible when the stack pointer is moved. By tracing s up the stack, it's possible to alter the ,  , or   of a function further up the stack. void *_get_ra(int dummy) {return -(&dummy)[1];} void *_get_bp(int dummy) {return -(&dummy)[2];} void *_get_sp {return _get_bp-2;} void *_get_ax {return;} void *_set_ra(void *val) {return (&val)[1] = -val;} void *_set_bp(void *val) {return (&val)[2] = -val;} void *_set_sp_ra; void *_set_sp_bp; void *_set_sp(void *val) { _set_sp_ra = (&val)[1]; _set_sp_bp = (&val)[2]; void *p = _set_bp(val+3); (&val)[1] = _set_sp_ra; (&val)[2] = _set_sp_bp; return p; } void *_set_ax(int val) {return val;} void *_alloca_ra; void *_alloca_bp; void *_alloca_ptr; void *alloca(int n) { _alloca_ra = (&n)[1]; _alloca_bp = (&n)[2]; _alloca_ptr = _get_bp-3; _set_bp(_get_bp+n); (&n)[1] = _alloca_ra; (&n)[2] = _alloca_bp; return _alloca_ptr; } /* a jmp_buf is an array of 3 cells */ int setjmp(void **env) { env[0] = _get_bp; //sp env[1] = (&env)[1]; //ra env[2] = (&env)[2]; //bp return 0; } void **_longjmp_env; int _longjmp_val; int longjmp(void **env, int val) { _longjmp_env = env; _longjmp_val = val?val:1; _set_bp(_longjmp_env[0]+1); //sp (&env)[1] = _longjmp_env[1]; //ra (&env)[2] = _longjmp_env[2]; //bp return _longjmp_val; } Ian 05:13, 9 August 2011 (UTC)
 * I made a small automatic-allocation string library based on  and using the ,  , and   functions defined previously. The functions are  ,  , and  . The last two are identical to the GNU libc functions. The first one is similar to  , reading a line until newline or EOF, but automatically allocates the buffer into the caller's automatic storage. They each have their own static variables even though the variables could be shared. Ideally, these would use the  -  loop style, but that's not implemented yet, so an infinite loop with a   is used instead. They can't use plain   because they need space for the null terminator and need to work with zero-length strings. Although  's prototype has an argument, it should be called with no arguments, since that's just a dummy variable used to provide access to the stack frame. These functions and   can safely be called multiple times (infinite times if the Subleq machine has infinite memory). A   will corrupt or destroy any data allocated by these functions since the last  . To explicitly free data,   can be called with a negative number, which will pop that number of cells from the stack. Like pointers to ordinary automatic variables, the pointers returned by these functions can't safely be returned to a previous caller, but it should be possible to make some type of combined  -  that can move the string into a previous stack frame and then return.

void *_getsa_ra; void *_getsa_bp; int _getsa_c; char *_getsa_ptr; char *_getsa_ret; char *getsa(int dummy) { _getsa_ra = (&dummy)[1]; _getsa_bp = (&dummy)[2]; _getsa_ret = _getsa_ptr = _get_bp-2; while (1) { _set_bp(_getsa_ptr+3); _set_sp(_getsa_ptr); if ((_getsa_c = *_getsa_ptr++ = __in) == '\n' || _getsa_c < 0) break; }	*--_getsa_ptr = '\0'; (&dummy)[1] = _getsa_ra; (&dummy)[2] = _getsa_bp; return _getsa_ret; } void *_strdupa_ra; void *_strdupa_bp; char *_strdupa_str; char *_strdupa_ptr; char *_strdupa_ret; char *strdupa(char* str) { _strdupa_ra = (&str)[1]; _strdupa_bp = (&str)[2]; _strdupa_str = str; _strdupa_ret = _strdupa_ptr = _get_bp-3; while (1) { _set_bp(_strdupa_ptr+4); _set_sp(_strdupa_ptr); if (!(*_strdupa_ptr++ = *_strdupa_str++)) break; }	(&str)[1] = _strdupa_ra; (&str)[2] = _strdupa_bp; return _strdupa_ret; } void *_strndupa_ra; void *_strndupa_bp; char *_strndupa_str; int _strndupa_n; char *_strndupa_ptr; char *_strndupa_ret; char *strndupa(char* str, int n) { _strndupa_ra = (&str)[1]; _strndupa_bp = (&str)[2]; _strndupa_str = str; _strndupa_n = n;	_strndupa_ret = _strndupa_ptr = _get_bp-4; while (1) { _set_bp(_strndupa_ptr+5); _set_sp(_strndupa_ptr); if (_strndupa_n-- <= 0 || !(*_strndupa_ptr++ = *_strndupa_str++)) break; }	*_strndupa_ptr = '\0'; (&str)[1] = _strndupa_ra; (&str)[2] = _strndupa_bp; return _strndupa_ret; } Ian 18:12, 9 August 2011 (UTC)
 * Here's a  to go with the other functions. This will allocate space for   bytes, copy them from the memory pointed to by , and then return a pointer to the new space. Like   and  , it is undefined behavior if the source and the newly allocated memory overlap, but this can only happen if the source is above the top of stack (like a dangling pointer). This function is mostly equivalent to  , except this implementation allocates and copies one cell at a time.

void *_memdupa_ra; void *_memdupa_bp; void *_memdupa_mem; int _memdupa_n; void *_memdupa_ptr; void *_memdupa_ret; void *memdupa(void* mem, int n) { _memdupa_ra = (&mem)[1]; _memdupa_bp = (&mem)[2]; _memdupa_mem = mem; _memdupa_n = n;	_memdupa_ret = _memdupa_ptr = _get_bp-4; while (--_memdupa_n >= 0) { _set_bp(_memdupa_ptr+5); _set_sp(_memdupa_ptr); *_memdupa_ptr++ = *_memdupa_mem++; }	(&mem)[1] = _memdupa_ra; (&mem)[2] = _memdupa_bp; return _memdupa_ret; } Ian 22:52, 9 August 2011 (UTC)