lang0/3-lang0ll/lang0ll0.c
Johan B.W. de Vries 9ddd04dfa4 Start on llvm IR target
# Conflicts:
#	0-lang0py/lang0py.py
#	1-lang0py/lang0py.lang0
#	2-lang0c/lang0c.lang0
#	Makefile
#	README.md
2025-02-02 15:43:37 +01:00

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;
}