187 lines
		
	
	
	
		
			2.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			187 lines
		
	
	
	
		
			2.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include "b.h"
 | |
| #include <stdarg.h>
 | |
| #include <string.h>
 | |
| #include <limits.h>
 | |
| 
 | |
| extern intptr_t i_main(intptr_t argc, const char* argv[]);
 | |
| 
 | |
| FILE* input_unit;
 | |
| FILE* output_unit;
 | |
| 
 | |
| static intptr_t i_char(intptr_t s, intptr_t n)
 | |
| {
 | |
|     const char* p = (const char*)(s<<SHIFT);
 | |
|     return p[n];
 | |
| }
 | |
| 
 | |
| static intptr_t i_lchar(intptr_t s, intptr_t n, intptr_t c)
 | |
| {
 | |
|     char* p = (char*)(s<<SHIFT);
 | |
|     p[n] = c;
 | |
| 	return c;
 | |
| }
 | |
| 
 | |
| static intptr_t i_getchar(void)
 | |
| {
 | |
|     return fgetc(input_unit);
 | |
| }
 | |
| 
 | |
| static intptr_t i_putchar(intptr_t c)
 | |
| {
 | |
|     fputc(c, output_unit);
 | |
|     return c;
 | |
| }
 | |
| 
 | |
| static intptr_t i_putstr(intptr_t s)
 | |
| {
 | |
| 	char* p = (char*)(s<<SHIFT);
 | |
| 	char c;
 | |
| 
 | |
| 	while ((c = *p++) != END)
 | |
| 		fputc(c, output_unit);
 | |
| 
 | |
| 	return s;
 | |
| }
 | |
| 
 | |
| static intptr_t i_getstr(intptr_t s)
 | |
| {
 | |
| 	char* p = (char*)(s<<SHIFT);
 | |
| 
 | |
| 	for (;;)
 | |
| 	{
 | |
| 		int c = fgetc(input_unit);
 | |
| 		if ((c == -1) || (c == '\n'))
 | |
| 			break;
 | |
| 		*p++ = c;
 | |
| 	}
 | |
| 
 | |
| 	*p++ = END;
 | |
| 	return s;
 | |
| }
 | |
| 	
 | |
| static void i_flush(void)
 | |
| {
 | |
| 	fflush(output_unit);
 | |
| }
 | |
| 
 | |
| static int tochar(int n)
 | |
| {
 | |
| 	if (n <= 9)
 | |
| 		return n + '0';
 | |
| 	return n - 10 + 'a';
 | |
| }
 | |
| 
 | |
| static void putnum(intptr_t value, int base)
 | |
| {
 | |
| 	int i;
 | |
| 	char s[32];
 | |
| 
 | |
| 	if (value < 0)
 | |
| 	{
 | |
| 		fputc('-', output_unit);
 | |
| 		value = -value;
 | |
| 	}
 | |
| 
 | |
| 	i = 0;
 | |
| 	do
 | |
| 		s[i++] = tochar(value % base);
 | |
| 	while ((value /= base) > 0);
 | |
| 
 | |
| 	do
 | |
| 		fputc(s[--i], output_unit);
 | |
| 	while (i > 0);
 | |
| }
 | |
| 
 | |
| static void i_printf(intptr_t s, ...)
 | |
| {
 | |
| 	char* p = (char*)(s<<SHIFT);
 | |
| 	char c;
 | |
| 
 | |
| 	va_list ap;
 | |
| 	va_start(ap, s);
 | |
| 
 | |
| 	while ((c = *p++) != END)
 | |
| 	{
 | |
| 		switch (c)
 | |
| 		{
 | |
| 			case '%':
 | |
| 			{
 | |
| 				intptr_t ss = va_arg(ap, intptr_t);
 | |
| 
 | |
| 				switch ((c = *p++))
 | |
| 				{
 | |
| 					case 's':
 | |
| 						i_putstr(ss);
 | |
| 						break;
 | |
| 
 | |
| 					case 'd':
 | |
| 						putnum(ss, 10);
 | |
| 						break;
 | |
| 
 | |
| 					case 'o':
 | |
| 						putnum(ss, 8);
 | |
| 						break;
 | |
| 
 | |
| 					case 'x':
 | |
| 						putnum(ss, 16);
 | |
| 						break;
 | |
| 
 | |
| 					case 'c':
 | |
| 						fputc(ss, output_unit);
 | |
| 						break;
 | |
| 
 | |
| 					default:
 | |
| 						fputc('?', output_unit);
 | |
| 						break;
 | |
| 				}
 | |
| 				break;
 | |
| 			}
 | |
| 				
 | |
| 			default:
 | |
| 				fputc(c, output_unit);
 | |
| 				break;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	va_end(ap);
 | |
| }
 | |
| 
 | |
| uintptr_t b_char = (uintptr_t)i_char;
 | |
| uintptr_t b_lchar = (uintptr_t)i_lchar;
 | |
| uintptr_t b_getchar = (uintptr_t)i_getchar;
 | |
| uintptr_t b_putchar = (uintptr_t)i_putchar;
 | |
| uintptr_t b_putstr = (uintptr_t)i_putstr;
 | |
| uintptr_t b_getstr = (uintptr_t)i_getstr;
 | |
| uintptr_t b_flush = (uintptr_t)i_flush;
 | |
| uintptr_t b_printf = (uintptr_t)i_printf;
 | |
| 
 | |
| static uintptr_t* bmodule_stdlib[] =
 | |
| {
 | |
|     &b_char,
 | |
|     &b_lchar,
 | |
|     &b_getchar,
 | |
|     &b_putchar,
 | |
| 	&b_putstr,
 | |
| 	&b_getstr,
 | |
| 	&b_flush,
 | |
| 	&b_printf,
 | |
|     0
 | |
| };
 | |
| 
 | |
| void patch_addresses(uintptr_t** p)
 | |
| {
 | |
|     while (*p)
 | |
|     {
 | |
|         uintptr_t* q = *p++;
 | |
|         *q >>= SHIFT;
 | |
|     }
 | |
| }
 | |
| 
 | |
| int main(int argc, const char* argv[])
 | |
| {
 | |
|     patch_addresses(bmodule_stdlib);
 | |
| 	binit();
 | |
|     input_unit = stdin;
 | |
|     output_unit = stdout;
 | |
|     return i_main(argc, NULL);
 | |
| }
 |