# Conflicts: # 0-lang0py/lang0py.py # 1-lang0py/lang0py.lang0 # 2-lang0c/lang0c.lang0 # Makefile # README.md
609 lines
13 KiB
C
609 lines
13 KiB
C
#include <assert.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
|
|
char var_eof[2] = {-1, 0};
|
|
char var_eol[2] = {10, 0};
|
|
char var_quote[2] = {34, 0};
|
|
char var_false[1] = {0};
|
|
char var_true[2] = {'1', 0};
|
|
|
|
|
|
char * eq(char * a, char * b)
|
|
{
|
|
return (strcmp(a, b) == 0) ? var_true : var_false;
|
|
}
|
|
|
|
char * lt(char * a, char * b)
|
|
{
|
|
return (strcmp(a, b) < 0) ? var_true : var_false;
|
|
}
|
|
char * not(char * a)
|
|
{
|
|
return (strcmp(a, var_true) != 0) ? var_true : var_false;
|
|
}
|
|
|
|
char * addstringchar(char * str, char * chr)
|
|
{
|
|
int str_len = strlen(str);
|
|
assert(strlen(chr) == 1);
|
|
char * res = malloc((str_len + 2) * sizeof(char));
|
|
strcpy(res, str);
|
|
res[str_len + 0] = chr[0];
|
|
res[str_len + 1] = 0;
|
|
return res;
|
|
}
|
|
|
|
char * emit(char * str)
|
|
{
|
|
fputs(str, stdout);
|
|
return 0;
|
|
}
|
|
|
|
char * trace(char * var_name, char * var_value)
|
|
{
|
|
const char * env_trace = getenv("TRACE");
|
|
if( !env_trace ) return 0;
|
|
fputs(var_name, stderr);
|
|
fputs("=", stderr);
|
|
fputs(var_value, stderr);
|
|
fputs(var_eol, stderr);
|
|
return 0;
|
|
}
|
|
|
|
int LINE = 1;
|
|
|
|
char * peek()
|
|
{
|
|
char * res = malloc(2*sizeof(char));
|
|
res[0] = getc(stdin);
|
|
res[1] = 0;
|
|
ungetc(res[0], stdin);
|
|
return res;
|
|
}
|
|
|
|
void skip()
|
|
{
|
|
char c = getc(stdin);
|
|
if( c == 10 ) LINE += 1;
|
|
}
|
|
|
|
void skipchar(char * chr)
|
|
{
|
|
assert(strlen(chr) == 1);
|
|
char * act = peek();
|
|
assert(strlen(act) == 1);
|
|
if( chr[0] == act[0] ) {skip(); return;};
|
|
fprintf(stderr, "Expected '%c' on line %d but saw '%c' instead%c", chr[0], LINE, act[0], 10);
|
|
exit(1);
|
|
}
|
|
|
|
char * increaseindent(char * var_indent)
|
|
{
|
|
var_indent = addstringchar(var_indent, " ");
|
|
var_indent = addstringchar(var_indent, " ");
|
|
var_indent = addstringchar(var_indent, " ");
|
|
var_indent = addstringchar(var_indent, " ");
|
|
return var_indent;
|
|
}
|
|
|
|
char * lexident()
|
|
{
|
|
char * var_char;
|
|
char * var_isbeforea;
|
|
char * var_isafterz;
|
|
char * var_word;
|
|
var_word = "";
|
|
while (1)
|
|
{
|
|
var_char = peek();
|
|
var_isbeforea = lt(var_char, "a");
|
|
if ( 0 < strlen(var_isbeforea) )
|
|
{
|
|
break;
|
|
}
|
|
var_isafterz = lt("z", var_char);
|
|
if ( 0 < strlen(var_isafterz) )
|
|
{
|
|
break;
|
|
}
|
|
var_word = addstringchar(var_word, var_char);
|
|
skip();
|
|
}
|
|
return var_word;
|
|
}
|
|
|
|
char * parseconststring()
|
|
{
|
|
char * var_char;
|
|
char * var_iseof;
|
|
char * var_isquote;
|
|
skipchar(var_quote);
|
|
while (1)
|
|
{
|
|
var_char = peek();
|
|
var_iseof = eq(var_char, var_eof);
|
|
if ( 0 < strlen(var_iseof) )
|
|
{
|
|
break;
|
|
}
|
|
var_isquote = eq(var_char, var_quote);
|
|
if ( 0 < strlen(var_isquote) )
|
|
{
|
|
break;
|
|
}
|
|
skip();
|
|
}
|
|
skipchar(var_quote);
|
|
emit("i8* noundef getelementptr inbounds ([14 x i8], [14 x i8]* @.str, i64 0, i64 0)");
|
|
return 0;
|
|
}
|
|
|
|
char * parseexprvarref()
|
|
{
|
|
char * var_varname;
|
|
var_varname = lexident();
|
|
emit("i8* %");
|
|
emit(var_varname);
|
|
return 0;
|
|
}
|
|
|
|
char * parseexprcall()
|
|
{
|
|
char * var_char;
|
|
char * var_first;
|
|
char * var_funcname;
|
|
char * var_isspace;
|
|
char * var_isnotspace;
|
|
char * var_isfirst;
|
|
char * var_isnotfirst;
|
|
char * var_isquote;
|
|
char * var_isnotquote;
|
|
var_funcname = lexident();
|
|
emit(var_funcname);
|
|
emit("(");
|
|
var_first = "1";
|
|
while (1)
|
|
{
|
|
var_char = peek();
|
|
var_isspace = eq(var_char, " ");
|
|
var_isnotspace = not(var_isspace);
|
|
if ( 0 < strlen(var_isnotspace) )
|
|
{
|
|
break;
|
|
}
|
|
skip();
|
|
var_isfirst = eq(var_first, "1");
|
|
var_isnotfirst = not(var_isfirst);
|
|
if ( 0 < strlen(var_isnotfirst) )
|
|
{
|
|
emit(", ");
|
|
}
|
|
var_char = peek();
|
|
var_isquote = eq(var_char, var_quote);
|
|
var_isnotquote = not(var_isquote);
|
|
if ( 0 < strlen(var_isquote) )
|
|
{
|
|
parseconststring();
|
|
}
|
|
if ( 0 < strlen(var_isnotquote) )
|
|
{
|
|
parseexprvarref();
|
|
}
|
|
var_first = "0";
|
|
}
|
|
emit(")");
|
|
return 0;
|
|
}
|
|
|
|
char * parsestatdeclare(char * var_indent)
|
|
{
|
|
char * var_var;
|
|
skipchar(" ");
|
|
var_var = lexident();
|
|
emit(var_indent);
|
|
emit("char * var_");
|
|
emit(var_var);
|
|
emit(";");
|
|
emit(var_eol);
|
|
skipchar(var_eol);
|
|
return 0;
|
|
}
|
|
|
|
char * parsestatset(char * var_indent)
|
|
{
|
|
char * var_var;
|
|
skipchar(" ");
|
|
var_var = lexident();
|
|
skipchar(" ");
|
|
emit(var_indent);
|
|
emit("var_");
|
|
emit(var_var);
|
|
emit(" = ");
|
|
parseconststring();
|
|
emit(";");
|
|
emit(var_eol);
|
|
skipchar(var_eol);
|
|
return 0;
|
|
}
|
|
|
|
char * parsestatcalc(char * var_indent)
|
|
{
|
|
char * var_var;
|
|
char * var_varidx;
|
|
skipchar(" ");
|
|
var_var = lexident();
|
|
skipchar(" ");
|
|
emit(var_indent);
|
|
emit("%");
|
|
emit(var_var);
|
|
var_varidx = mapgetkey("funcvarused", var_var);
|
|
var_varidx = intinc(var_varidx);
|
|
mapsetkey("funcvarused"var_var, var_varidx, );
|
|
emit(".");
|
|
emit(var_varidx);
|
|
emit(" = call i8* @");
|
|
parseexprcall();
|
|
emit(";");
|
|
emit(var_eol);
|
|
skipchar(var_eol);
|
|
return 0;
|
|
}
|
|
|
|
char * parseblock(char * var_indent);
|
|
char * parsestatif(char * var_indent)
|
|
{
|
|
char * var_indentt;
|
|
skipchar(" ");
|
|
emit(var_indent);
|
|
emit("if ( 0 < strlen(");
|
|
parseexprvarref();
|
|
emit(") )\n");
|
|
emit(var_indent);
|
|
emit("{\n");
|
|
skipchar(var_eol);
|
|
var_indentt = increaseindent(var_indent);
|
|
parseblock(var_indentt);
|
|
emit(var_indent);
|
|
emit("}\n");
|
|
return 0;
|
|
}
|
|
|
|
char * parsestatforever(char * var_indent)
|
|
{
|
|
char * var_indentt;
|
|
emit(var_indent);
|
|
emit("while (1)\n");
|
|
emit(var_indent);
|
|
emit("{\n");
|
|
skipchar(var_eol);
|
|
var_indentt = increaseindent(var_indent);
|
|
parseblock(var_indentt);
|
|
emit(var_indent);
|
|
emit("}\n");
|
|
return 0;
|
|
}
|
|
|
|
char * parsestatbreak(char * var_indent)
|
|
{
|
|
emit(var_indent);
|
|
emit("break;\n");
|
|
skipchar(var_eol);
|
|
return 0;
|
|
}
|
|
|
|
char * parsestatreturn(char * var_indent)
|
|
{
|
|
char * var_char;
|
|
char * var_isspace;
|
|
char * var_isnotspace;
|
|
emit(var_indent);
|
|
emit("ret ");
|
|
var_char = peek();
|
|
var_isspace = eq(var_char, " ");
|
|
var_isnotspace = not(var_isspace);
|
|
if ( 0 < strlen(var_isspace) )
|
|
{
|
|
skip();
|
|
parseexprvarref();
|
|
}
|
|
if ( 0 < strlen(var_isnotspace) )
|
|
{
|
|
emit("i18* 0");
|
|
}
|
|
emit(";");
|
|
emit(var_eol);
|
|
skipchar(var_eol);
|
|
return 0;
|
|
}
|
|
|
|
char * parsestattrace(char * var_indent)
|
|
{
|
|
char * var_varname;
|
|
emit(var_indent);
|
|
emit("trace(");
|
|
emit(var_quote);
|
|
skipchar(" ");
|
|
var_varname = lexident();
|
|
emit(var_varname);
|
|
emit(var_quote);
|
|
emit(", var_");
|
|
emit(var_varname);
|
|
emit(");\n");
|
|
skipchar(var_eol);
|
|
return 0;
|
|
}
|
|
|
|
char * parsestat(char * var_indent)
|
|
{
|
|
char * var_call;
|
|
char * var_char;
|
|
char * var_first;
|
|
char * var_iscall;
|
|
char * var_isfirst;
|
|
char * var_isspace;
|
|
char * var_isquote;
|
|
char * var_isnotfirst;
|
|
char * var_isnotspace;
|
|
char * var_isnotquote;
|
|
var_call = lexident();
|
|
trace("call", var_call);
|
|
var_iscall = eq(var_call, "declare");
|
|
if ( 0 < strlen(var_iscall) )
|
|
{
|
|
parsestatdeclare(var_indent);
|
|
return 0;
|
|
}
|
|
var_iscall = eq(var_call, "set");
|
|
if ( 0 < strlen(var_iscall) )
|
|
{
|
|
parsestatset(var_indent);
|
|
return 0;
|
|
}
|
|
var_iscall = eq(var_call, "calc");
|
|
if ( 0 < strlen(var_iscall) )
|
|
{
|
|
parsestatcalc(var_indent);
|
|
return 0;
|
|
}
|
|
var_iscall = eq(var_call, "if");
|
|
if ( 0 < strlen(var_iscall) )
|
|
{
|
|
parsestatif(var_indent);
|
|
return 0;
|
|
}
|
|
var_iscall = eq(var_call, "forever");
|
|
if ( 0 < strlen(var_iscall) )
|
|
{
|
|
parsestatforever(var_indent);
|
|
return 0;
|
|
}
|
|
var_iscall = eq(var_call, "break");
|
|
if ( 0 < strlen(var_iscall) )
|
|
{
|
|
parsestatbreak(var_indent);
|
|
return 0;
|
|
}
|
|
var_iscall = eq(var_call, "return");
|
|
if ( 0 < strlen(var_iscall) )
|
|
{
|
|
parsestatreturn(var_indent);
|
|
return 0;
|
|
}
|
|
var_iscall = eq(var_call, "trace");
|
|
if ( 0 < strlen(var_iscall) )
|
|
{
|
|
parsestattrace(var_indent);
|
|
return 0;
|
|
}
|
|
emit(var_indent);
|
|
emit(var_call);
|
|
emit("(");
|
|
var_first = "1";
|
|
while (1)
|
|
{
|
|
var_char = peek();
|
|
var_isspace = eq(var_char, " ");
|
|
var_isnotspace = not(var_isspace);
|
|
if ( 0 < strlen(var_isnotspace) )
|
|
{
|
|
break;
|
|
}
|
|
skip();
|
|
var_char = peek();
|
|
var_isquote = eq(var_char, var_quote);
|
|
var_isnotquote = not(var_isquote);
|
|
if ( 0 < strlen(var_isquote) )
|
|
{
|
|
parseconststring();
|
|
}
|
|
if ( 0 < strlen(var_isnotquote) )
|
|
{
|
|
parseexprvarref();
|
|
}
|
|
var_isfirst = eq(var_first, "1");
|
|
var_isnotfirst = not(var_isfirst);
|
|
if ( 0 < strlen(var_isnotfirst) )
|
|
{
|
|
emit(", ");
|
|
}
|
|
var_first = "0";
|
|
}
|
|
skipchar(var_eol);
|
|
emit(");\n");
|
|
return 0;
|
|
}
|
|
|
|
char * parseblock(char * var_indent)
|
|
{
|
|
char * var_char;
|
|
char * var_copy;
|
|
char * var_iseol;
|
|
char * var_isnoteol;
|
|
char * var_isdone;
|
|
char * var_iseoblock;
|
|
while (1)
|
|
{
|
|
while (1)
|
|
{
|
|
var_char = peek();
|
|
var_iseol = eq(var_char, var_eol);
|
|
var_isnoteol = not(var_iseol);
|
|
if ( 0 < strlen(var_isnoteol) )
|
|
{
|
|
break;
|
|
}
|
|
skip();
|
|
}
|
|
var_copy = " ";
|
|
while (1)
|
|
{
|
|
var_isdone = eq(var_copy, var_indent);
|
|
if ( 0 < strlen(var_isdone) )
|
|
{
|
|
break;
|
|
}
|
|
skipchar("\t");
|
|
var_copy = increaseindent(var_copy);
|
|
}
|
|
var_char = peek();
|
|
var_iseoblock = eq(var_char, "/");
|
|
if ( 0 < strlen(var_iseoblock) )
|
|
{
|
|
skip();
|
|
skipchar(var_eol);
|
|
break;
|
|
}
|
|
skipchar("\t");
|
|
parsestat(var_indent);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
char * parsefunc()
|
|
{
|
|
char * var_char;
|
|
char * var_first;
|
|
char * var_funcname;
|
|
char * var_iseoblock;
|
|
char * var_isfirst;
|
|
char * var_isspace;
|
|
char * var_isnotfirst;
|
|
char * var_isnotspace;
|
|
char * var_var;
|
|
mapclear("funcvarused");
|
|
var_funcname = lexident();
|
|
trace("funcname", var_funcname);
|
|
emit("define i8* @");
|
|
emit(var_funcname);
|
|
emit("(");
|
|
var_first = "1";
|
|
while (1)
|
|
{
|
|
var_char = peek();
|
|
var_isspace = eq(var_char, " ");
|
|
var_isnotspace = not(var_isspace);
|
|
if ( 0 < strlen(var_isnotspace) )
|
|
{
|
|
break;
|
|
}
|
|
skip();
|
|
var_var = lexident();
|
|
var_isfirst = eq(var_first, "1");
|
|
var_isnotfirst = not(var_isfirst);
|
|
if ( 0 < strlen(var_isnotfirst) )
|
|
{
|
|
emit(", ");
|
|
}
|
|
emit("i8* %");
|
|
emit(var_var);
|
|
mapsetkey("funcvarused""var", "0", );
|
|
emit("_0");
|
|
var_first = "0";
|
|
}
|
|
var_char = peek();
|
|
var_iseoblock = eq(var_char, "/");
|
|
if ( 0 < strlen(var_iseoblock) )
|
|
{
|
|
skipchar("/");
|
|
skipchar(var_eol);
|
|
emit(");");
|
|
emit("\n");
|
|
return 0;
|
|
}
|
|
skipchar(":");
|
|
skipchar(var_eol);
|
|
emit(")\n{\n");
|
|
parseblock(" ");
|
|
emit("}\n\n");
|
|
return 0;
|
|
}
|
|
|
|
char * emitheader()
|
|
{
|
|
emit("target datalayout = ");
|
|
emit(var_quote);
|
|
emit("e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128");
|
|
emit(var_quote);
|
|
emit(var_eol);
|
|
emit("target triple = ");
|
|
emit(var_quote);
|
|
emit("x86_64-pc-linux-gnu");
|
|
emit(var_quote);
|
|
emit(var_eol);
|
|
emit(var_eol);
|
|
emit("define i8* @addstringchar(i8* %0, i8* %1)");
|
|
emit(var_eol);
|
|
emit("{");
|
|
emit(var_eol);
|
|
emit(" ; todo");
|
|
emit(var_eol);
|
|
emit(" ret i8* %0;");
|
|
emit(var_eol);
|
|
emit("}");
|
|
emit(var_eol);
|
|
emit(var_eol);
|
|
return 0;
|
|
}
|
|
|
|
char * emitfooter()
|
|
{
|
|
emit("");
|
|
return 0;
|
|
}
|
|
|
|
char * main()
|
|
{
|
|
char * var_char;
|
|
char * var_iseof;
|
|
char * var_iseol;
|
|
char * var_isnoteol;
|
|
emitheader();
|
|
while (1)
|
|
{
|
|
var_char = peek();
|
|
var_iseof = eq(var_char, var_eof);
|
|
if ( 0 < strlen(var_iseof) )
|
|
{
|
|
break;
|
|
}
|
|
while (1)
|
|
{
|
|
var_char = peek();
|
|
var_iseol = eq(var_char, var_eol);
|
|
var_isnoteol = not(var_iseol);
|
|
if ( 0 < strlen(var_isnoteol) )
|
|
{
|
|
break;
|
|
}
|
|
skip();
|
|
}
|
|
parsefunc();
|
|
}
|
|
emitfooter();
|
|
return 0;
|
|
}
|
|
|