forsyth20121205-174063a80cc13 years agoHistory
946 lines · 16.0 KB · Brainfuck
RawDownload
implement M4; include "sys.m";	sys: Sys; include "draw.m"; include "bufio.m";	bufio: Bufio;	Iobuf: import bufio; include "sh.m"; include "arg.m"; M4: module{	init:	fn(nil: ref Draw->Context, nil: list of string);}; NHASH: con 131; Name: adt {	name:	string;	repl:	string;	impl:	ref fn(nil: array of string);	dol:	int;	# repl contains $[0-9]	asis:	int;	# replacement text not rescanned 	text:	fn(n: self ref Name): string;}; names := array[NHASH] of list of ref Name; File: adt {	name:	string;	line:	int;	fp:	ref Iobuf;}; Param: adt {	s:	string;}; pushedback: string;pushedp := 0;	# next available index in pushedbackdiverted := array[10] of string;curdiv := 0;curarg: ref Param;	# non-nil if collecting argument stringinstack: list of ref File;lquote := '`';rquote := '\'';initcom := "#";endcom := "\n";bout: ref Iobuf;sh: Sh; init(nil: ref Draw->Context, args: list of string){	sys = load Sys Sys->PATH;	bufio = load Bufio Bufio->PATH; 	bout = bufio->fopen(sys->fildes(1), Sys->OWRITE); 	define("inferno", "inferno", 0); 	builtin("changecom", dochangecom);	builtin("changequote", dochangequote);	builtin("copydef", docopydef);	builtin("define", dodefine);	builtin("divert", dodivert);	builtin("divnum", dodivnum);	builtin("dnl", dodnl);	builtin("dumpdef", dodumpdef);	builtin("errprint", doerrprint);	builtin("eval", doeval);	builtin("ifdef", doifdef);	builtin("ifelse", doifelse);	builtin("include", doinclude);	builtin("incr", doincr);	builtin("index", doindex);	builtin("len", dolen);	builtin("maketemp", domaketemp);	builtin("sinclude", dosinclude);	builtin("substr", dosubstr);	builtin("syscmd", dosyscmd);	builtin("translit", dotranslit);	builtin("undefine", doundefine);	builtin("undivert", doundivert); 	arg := load Arg Arg->PATH;	arg->setusage("m4 [-Dname[=value]] [-Qname[=value]] [-Uname] [file ...]");	arg->init(args); 	while((o := arg->opt()) != 0){		case o {		'D' =>			argdefine(arg->earg(), 0);		'Q' =>			argdefine(arg->earg(), 1);		'U' =>			undefine(arg->earg());		* =>			arg->usage();		}	}	args = arg->argv();	arg = nil; 	if(args != nil){		for(; args != nil; args = tl args){			f := bufio->open(hd args, Sys->OREAD);			if(f == nil)				error(sys->sprint("can't open %s: %r", hd args));			pushfile(hd args, f);			scan();		}	}else{		pushfile("standard input", bufio->fopen(sys->fildes(0), Sys->OREAD));		scan();	}	bout.flush();} argdefine(s: string, asis: int){	text := "";	for(i := 0; i < len s; i++)		if(s[i] == '='){			text = s[i+1:];			break;		}	n := lookup(s[0: i]);	if(n != nil && n.impl != nil)		error(sys->sprint("can't redefine built-in %s", s[0: i]));	define(s[0: i], text, asis);} scan(){	while((c := getc()) >= 0){		if(isalpha(c))			called(c);			else if(c == lquote)			quoted();		else if(initcom != nil && initcom[0] == c)			comment();		else			putc(c);	}} error(s: string){	where := "";	if(instack != nil){		ios := hd instack;		where = sys->sprint(" %s:%d:", ios.name, ios.line);	}	sys->fprint(sys->fildes(2), "m4:%s %s\n", where, s);	raise "fail:error";} pushfile(name: string, fp: ref Iobuf){	instack = ref File(name, 1, fp) :: instack;} called(c: int){	tok: string;	do{		tok[len tok] = c;		c = getc();	}while(isalpha(c) || c >= '0' && c <= '9');	def := lookup(tok);	if(def == nil){		pushc(c);		puts(tok);		return;	}	if(c != '(' || def.asis){	# no parameters		pushc(c);		expand(def, array[] of {tok});		return;	}	# collect arguments, allowing for nested parentheses;	# on ')' expand definition, further expanding $n references therein	argstack := def.name :: nil;	# $0	savearg := curarg;	# save parameter (if any) for outer call	curarg = ref Param("");	nesting := 0;	# () depth	skipws();	for(;;){		if((c = getc()) < 0)			error("EOF in parameters");		if(isalpha(c))			called(c);		else if(c == lquote)			quoted();		else{			if(c == '(')				nesting++;			if(nesting > 0){				if(c == ')')					nesting--;				putc(c);			}else if(c == ','){				argstack = curarg.s :: argstack;				curarg = ref Param("");				skipws();			}else if(c == ')')				break;			else				putc(c);		}	}	argstack = curarg.s :: argstack;	curarg = savearg;	# restore outer parameter (if any)	# build arguments	narg := len argstack;	args := array[narg] of string;	for(; argstack != nil; argstack = tl argstack)		args[--narg] = hd argstack;	expand(def, args);} quoted(){	nesting :=0;	while((c := getc()) != rquote || nesting > 0){		if(c < 0)			error("EOF in string");		if(c == rquote)			nesting--;		else if(c == lquote)			nesting++;		putc(c);	}} comment(){	for(i := 1; i < len initcom; i++){		if((c := getc()) != initcom[i]){			if(c < 0)				error("EOF in comment");			pushc(c);			pushs(initcom[1: i]);			putc(initcom[0]);			return;		}	}	puts(initcom);	for(i = 0; i < len endcom;){		c := getc();		if(c < 0)			error("EOF in comment");		putc(c);		if(c == endcom[i])			i++;		else			i = c == endcom[0];	}} skipws(){	while(isspace(c := getc()))		{}	pushc(c);} isspace(c: int): int{	return c == ' ' || c == '\t' || c == '\n' || c == '\r';} isname(s: string): int{	if(s == nil || !isalpha(s[0]))		return 0;	for(i := 1; i < len s; i++)		if(!(isalpha(s[i]) || s[i]>='0' && s[i]<='9'))			return 0;	return 1;} isalpha(c: int): int{	return c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_' || c > 16rA0;} hash(name: string): int{	h := 0;	for(i := 0; i < len name; i++)		h = h*65599 + name[i];	return (h & ~(1<<31)) % NHASH;} builtin(name: string, impl: ref fn(nil: array of string)){	h := hash(name);	n := ref Name(name, nil, impl, 0, 0);	names[h] = n :: names[h];} define(name: string, repl: string, asis: int){	h := hash(name);	dol := hasdol(repl);	for(l := names[h]; l != nil; l = tl l){		n := hd l;		if(n.name == name){			*n = Name(name, repl, nil, dol, asis);			return;		}	}	n := ref Name(name, repl, nil, dol, asis);	names[h] = n :: names[h];} lookup(name: string): ref Name{	h := hash(name);	for(l := names[h]; l != nil; l = tl l)		if((hd l).name == name)			return hd l;	return nil;} undefine(name: string){	h := hash(name);	rl: list of ref Name;	for(l := names[h]; l != nil; l = tl l){		if((hd l).name == name){			l = tl l;			for(; rl != nil; rl = tl rl)				l = hd rl :: l;			names[h] = l;			return;		}else			rl = hd l :: rl;	}} Name.text(n: self ref Name): string{	if(n.impl != nil)		return sys->sprint("builtin %q", n.name);	return sys->sprint("%c%s%c", lquote, n.repl, rquote);} dodumpdef(args: array of string){	if(len args > 1){		for(i := 1; i < len args; i++)			if((n := lookup(args[i])) != nil)				sys->fprint(sys->fildes(2), "%q	%s\n", n.name, n.text());	}else{		for(i := 0; i < len names; i++)			for(l := names[i]; l != nil; l = tl l)				sys->fprint(sys->fildes(2), "%q %s\n", (hd l).name, (hd l).text());	}} pushs(s: string){	for(i := len s; --i >= 0;)		pushedback[pushedp++] = s[i];} pushc(c: int){	if(c >= 0)		pushedback[pushedp++] = c;} getc(): int{	if(pushedp > 0)		return pushedback[--pushedp];	for(; instack != nil; instack = tl instack){		ios := hd instack;		c := ios.fp.getc();		if(c >= 0){			if(c == '\n')				ios.line++;			return c;		}	}	return -1;} puts(s: string){	if(curarg != nil)		curarg.s += s;	else if(curdiv > 0)		diverted[curdiv] += s;	else if(curdiv == 0)		bout.puts(s);} putc(c: int){	if(curarg != nil){		# stow in argument collection buffer		curarg.s[len curarg.s] = c;	}else if(curdiv > 0){		l := len diverted[curdiv];		diverted[curdiv][l] = c;	}else if(curdiv == 0)		bout.putc(c);} expand(def: ref Name, args: array of string){	if(def.impl != nil){		def.impl(args);		return;	}	if(def.repl == def.name || def.repl == "$0"){		puts(def.name);		return;	}	if(!def.dol || def.repl == nil){		pushs(def.repl);		return;	}	# expand $n	s := def.repl;	for(i := len s; --i >= 1;){		if(s[i-1] == '$' && (c := s[i]-'0') >= 0 && c <= 9){			if(c < len args)				pushs(args[c]);			i--;		}else			pushc(s[i]);	}	if(i >= 0)		pushc(s[0]);} hasdol(s: string): int{	for(i := 0; i < len s; i++)		if(s[i] == '$')			return 1;	return 0;} dodefine(args: array of string){	if(len args > 2)		define(args[1], args[2], 0);	else if(len args > 1)		define(args[1], "", 0);} doundefine(args: array of string){	for(i := 1; i < len args; i++)		undefine(args[i]);} docopydef(args: array of string){	if(len args > 2 && args[1] != args[2]){		undefine(args[2]);		if((n := lookup(args[1])) != nil){			if(n.impl == nil)				define(args[2], n.repl, n.asis);			else				builtin(args[2], n.impl);		}else			define(args[2], "", 0);	}} doeval(args: array of string){	if(len args > 1)		pushs(string eval(args[1]));} dodivert(args: array of string){	if(len args > 1){		n := int args[1];		if(n < 0 || n >= len diverted)			n = -1;		curdiv = n;	}else		curdiv = 0;} dodivnum(nil: array of string)

Lines 1–500 of 946.