5XO7IKBGCVXGVWMDJDE5MELS4FWRITKAU6NNV36NQ4TOZRR7UQ7QC 7BYMVBE225GXMGCZIPBE7XAGZ3FMO2NF75PSTBYQT3ZQ3ZK6YKOAC JDZASPALXSFZOL3MXCKBPX74CUD3W743ZJ6W2422FIJ7NJOD67ZAC A2JAXDJWT2FAKADYOY6QOQ7LQRMTTCDIOYT7STSESVHLZQEQJBMAC O6PFGAUDYCMK6SC6V5RB5ELXZ7W54OB7XPYCMECCA4BSBUVLFAPAC UW27LKXM2BJ77FQLTY4WPKDSSWI2RFNFRJ7CB4U3TS7KYVIV72LQC NBEO3TPNOUG7MRFYRSDDFB5TQKTEDL6GHHFQVOB5MXVPIBKFNZKAC GW4AAYNF7I66D72G5PMFTQRK7B4KZVYKAHKRPC2IY7IX37JKEHJQC 6XHALMLUA5B5BBYFSWIFHSJ2BXCL6RSAW5TCKRGJEI2LURH2TQ4AC MPN7OJSZD5CS5N7WWS3ZSOYE7ZRCABIBHZDMHVS6IT25EO2INK7AC function _gc_mark_list(lis, car, tv, t, v, i) {logg_dbg("_gc_mark_list", "cons number " lis)i = 0
function _gc_mark_cell(n, dot_filename, d) {logg_dbg("_gc_mark_cell", n, d)_MARK[n] = 1if(dot_filename)print " n" n " [fillcolor=green];" >>dot_filenamereturn 1}function _gc_mark_list(lis, dot_filename, d, i) {
car = _car(lis)lis = _cdr(lis)if(_falsy(car)) continuet = _TYPE[car]_MARK[car] = 1if(t == "(") {i += _gc_mark_list(car)
i += _gc_mark_cell(lis, dot_filename, d)if(!_is_literal(_car(lis))) {if(_TYPE[_car(lis)] == "(") {i += _gc_mark_list(_car(lis), dot_filename, d+1)} else {i += _gc_mark_cell(_car(lis), dot_filename, d)}
i += 1}
if(_is_literal(_cdr(lis))) {if(_is_null(_cdr(lis))) {lis = _nil()} else {# pairlogg_dbg("_gc_mark_list", "cdr is a literal. pair?", d)i += _gc_mark_cell(_cdr(lis), dot_filename, d)lis = _nil()}} else {if(_TYPE[_cdr(lis)] == "(") {# move along lislis = _cdr(lis)} else {# a pair with a non-literallogg_dbg("_gc_mark_list","cdr " _cdr(lis) " is not a cons. pair?", d)i += _gc_mark_cell(_cdr(lis), dot_filename, d)}}}
function _gc(envs, i, t, name, ngcd, nmarks) {# y'know... the envs given had better add up to everything, not# just globals and not just one stack of envs. hmmdelete _MARKngcd = 0logg_dbg("_gc", "marking")nmarks = _gc_mark_list(envs)logg_dbg("_gc", "sweeping")
function _gc_sweep(dot_filename, ngcd) {
}
}}function _gc_dot(envs, mark_filename, sweep_filename, i, t, name, ngcd, nmarks) {# y'know... the envs given had better add up to everything, not# just globals and not just one stack of envs. hmmdelete _MARKngcd = 0logg_dbg("_gc", "marking")if(mark_filename) print "" >mark_filenameif(sweep_filename) print "" >sweep_filenamenmarks = _gc_mark_list(envs, mark_filename, 0)logg_dbg("_gc", "sweeping")ngcd = _gc_sweep(sweep_filename)# _dump("post-gc")
function _gc(envs) {return _gc_dot(envs)}
# make list of these percent symbols because _eval3 compares the# address of the operator being eval'd against them, in order to# reduce the number of if-elseif-elseif-elseif... cases if the# operator isn't one of the most common ones._COMPARED_SYMBOLS = _cons(_symbol("%other-lispy%"),_cons(_symbol("%math%"),_cons(_symbol("%last-special-form%"),_nil())))
# i is not a number but a string. somewhere in the code we# ask if _TYPE[something] == bla, where something may be# true, or false, or nil, or a literal number ("# 123");# and by asking about _TYPE[something], we make# _TYPE[something] exist, and be "". we don't want to dump# those here because _TYPE[# 123] is not valid awk syntax.if((i+0)!=i) continue
}function dotescape(string) {gsub(/\\/, "\\\\", string)gsub(/"/, "\\\"", string)return string}function dotrepr(v) {if(v == _nil())return _nil()else if(v == _true())return _true()else if(v == _false())return _false()else if(v+0 == v)return velse {dotescape(v)return v}
function _dump_dot(filename, i, t, v, s, n, node, edge, edge2) {logg_dbg("_dump_dot", "dumping Graphviz to " filename)print "digraph g {" >filenameprint " rankdir=LR" >>filenameprint " overlap=false" >>filenameprint " node [style=filled]" >>filenamefor(i in _TYPE) {# i is not a number but a string. somewhere in the code we# ask if _TYPE[something] == bla, where something may be# true, or false, or nil, or a literal number ("# 123");# and by asking about _TYPE[something], we make# _TYPE[something] exist, and be "". we don't want to dump# those here.if((i+0)!=i) continuet = _TYPE[i]print "/* " i " is a " _TYPE[i] " : " _repr(i) " */" >>filenameif(t == "(") {print "/* -- " _CAR[i] " is a " _TYPE[_CAR[i]] " : " _repr(_CAR[i]) " */" >>filenamet = _TYPE[_CAR[i]]node = " n" i " [shape=record,label=\"{<n> " i "|"edge = ""edge2 = ""if(t == "(") {node = node "<car> ·|"edge = " n" i ":car -> n" _CAR[i] ":n;"} else if(t == "'") {v = _SYM_NUMBERS[_CAR[i]]dotescape(v)node = node v "|"#edge =" n" i ":car -> n" _CAR[i] ";"} else if(t == "s") {v = _STRING[_CAR[i]]dotescape(v)node = node "\\\"" v "\\\"|"} else {node = node dotrepr(_CAR[i]) "|"}if(_is_null(_CDR[i])) {node = node "<cdr> X}\"];"} else {node = node "<cdr> ·}\"];"edge2 = " n" i ":cdr -> n" _CDR[i] ":n;"}print node >>filenameprint edge >>filenameprint edge2 >>filename} else if(t == "'") {#print " n" i " [shape=record,label=\"{<n> " i "|" _SYM_NUMBERS[i] "}\"];" >>filename} else if(t == "s") {print " n" i " [shape=record,label=\"{<n> " i "|" _STRING[i] "}\"];" >>filename}}print " nGlobals [label=\"_GLOBALS\"];" >>filenameprint " nGlobals -> n" _GLOBALS ";" >>filenameprint " nMacros [label=\"_MACROS\"];" >>filenameprint " nMacros -> n" _MACROS ";" >>filenameprint " nCompared [label=\"_COMPARED_SYMBOLS\"];" >>filenameprint " nCompared -> n" _COMPARED_SYMBOLS ";" >>filenameprint "/*sweep colors*/" >>filenameprint "/*mark colors*/" >>filenameprint "}" >>filenameclose(filename)return _true()}
help = "\n\Targets:\n\glotawk: build the interpreter, a single large\n\executable AWK script\n\check: run tests\n\benchmark: run a few benchmarks\n\all (default): glotawk, check, and benchmark\n\clean: get rid of build products\n\heapviz: fancy Graphviz view of initial heap and GC\n\"help:@echo ${help} >&2
.PHONY: all depend check test clean benchmark
heap-nomarks.dot: glotawkecho "(dump-dot \"$@\")" | ./glotawkgc-marks.dot gc-sweeps.dot: glotawkecho "(gc-dot \"gc-marks.dot\" \"gc-sweeps.dot\")" | ./glotawk -v LOG_LEVEL=3heap.dot: glotawk heap-nomarks.dot gc-marks.dot gc-sweeps.dotcat heap-nomarks.dot | \sed -e '/^\/\*mark colors\*\/$$/r gc-marks.dot' | \sed -e '/^\/\*sweep colors\*\/$$/r gc-sweeps.dot' > $@heapviz: heap.dotdot -Tx11 heap.dot.PHONY: all depend check test clean benchmark heapviz