// CLASS - the 1LT8 Assembler
// written by Lutz Vieweg 1991-1994
//
// This source is based on the original GFA-BASIC version
// of CLASS I wrote 3 years ago. The consequences are:
//
// - the programming style looks partly awful. The most part of the
//   conversion from GFA-BASIC was done by search & replace,
//   so the program has still some typical structures of a BASIC
//   program.
//
// - the code is not very efficient. Luckily, assembling is not
//   such a time critical task...
//
// - if macro-support is enabled ("-macros"), the exit is currently
//   "dirty", memory resources are not freed by the program.
//   That means: DON'T USE "-macros" ON A SYSTEM WITHOUT
//   RESOURCE-TRACKING.  I'll fix this later.
//
// For more information, look into class.doc


// The class "Str" is used to emulate GFA-BASIC strings,
// they can be of arbitrary size (not limited to 32767 byte
// as the "String" class from libg++.a), and they may contain
// zeroes.
#include <Str.h>

// NibStr hold strings of nibbles
#include "NibStr.h"

#include "SourceLine.h"

// Symbol and ObjectFile classes are defined here
#include "object.h"

// floating-point parsing routines written by Alex Ramos
#include "fp_support.h"

// We do our I/O via streams
#include <iostream.h>
#include <fstream.h>

// Bstreams are the (re-)storable variant of streams
#include <Bstream.h>

// a siple error-handler, should be used more often when
// the code is finally cleaned up
#include <set_error.h>

extern "C" {
	#include <stdlib.h>
	#include <stddef.h>
	#include <stdio.h>	// need sscanf() from there
#ifndef hpux         // HP-UX includes are prepared for inclusion from C++
	#include <math.h>
#endif
}
#ifdef hpux
	#include <math.h>
#endif

extern const char * version_tag;

// global variable en masse - awful, isn't it? :(

ObjectFile obj;
AVLTree<Symbol> l_arr;
List<SourceLine> src;
ListItem<SourceLine> * akt_line;
int line;

bool verbose = 0;

Str last_ext_ref = "*";
bool last_exp_had_lbl = false; // true if last evaluated expr. contained a label
unsigned long adr = 0;
unsigned long nib_len = 0;
Str * m_name;
Str * m_txt;
Str * m_para;
Str last_label;
Str p1;
Str p2;

Str src_name;
Str incdir_name;
int base_add = 0;
bool ul_list = false;
bool exe_flag = false;
bool tmp_lbl = false;
int max_macros = 100;
int macros;
int mac_count = 0;
bool no_mac = true;

static const char rev_nibs[16] = {
//    0    1    2    3    4    5    6    7    8    9    a    b    c    d    e    f
	0x00,0x08,0x04,0x0c,0x02,0x0a,0x06,0x0e,0x01,0x09,0x05,0x0d,0x03,0x0b,0x07,0x0f
};

Str no_ext(const Str & a) {
	unsigned long i = a.rindex('.');
	unsigned long j = a.rindex('/');
	if ( i != (unsigned long)~0 && (j == (unsigned long)~0 || j < i) ) {
		return a.before(i);
	} else {
		return a;
	}
}

Str nparas(Str & x) {

	bool f;
	unsigned long i;
	static Str a;

	if ( ! x.length() ) {
		return x;
	} else {
		char * c = (char *)x;
		char z = 0;
		for ( i=0; i < x.length() ; i++) {
			z = *c++;
			if ( (z != 32 && z!=9) || z==59 ) break;
		}
		
		if ( i==x.length() || z==59 ) {
			x = "";
			return x;
		} else {
			x = x.after(i-1);
		}
		
		if ( x == "" ) {
			return x;
		} else {
			f = true;
			char * c = (char *)x;
			char z = 0;
			for ( i=0; i < x.length(); i++) {
				z = *c++;
				if ( z==34 ) {
					f = !f;
				}
				if ( f ) {
					if ( z==44 || z==9 || z==59 || z==32 ) break;
				}
			}
			
			if ( i==x.length() ) {
				a = x;
				x = "";
				return a;
			} else {
				a = x.left(i);
				if ( z==59 ) {
					x = "";
				} else {
					x = x.after(i);
					i++;
				}
				return a;
			}
		}
	}
}

Str & npara(Str & x) {
	int i;
	static Str a;
	
	if ( ! x.length() ) {
		a.clear();
		return a; // Str((unsigned long)0);
	} else {
		i = x.index((char)1);
		a = x.before(i);
		x = x.after(i);
		return a;
	}
}

int nrof_paras(const Str & x) {
	unsigned long i;
	int c = 0;
	if ( x.length() ) {
		for ( i=0; i < x.length(); i++ ) {
			if (x.chr(i) == 1) c++;
		}
		return c;
	} else {
		return 0;
	}
}

/*
inline Str nword(Str & x) {
	return x.next_word();
}
*/

int error_count = 0;

void norm_err(const Str & err) {
	int i;
	int o;
	Str f;
	Str a;
	
	++error_count;

	cerr << "ERROR: " << err << '\n';
	
	if (!akt_line) return;
	
	o = -1;
	ListItem<SourceLine> * err_line = akt_line;
	for (i = line; i >= 0; i--) {
		if ( err_line->obc == "AKTFILE" ) break;
		o++;
		err_line = err_line->get_prev();
	}
	
	a = err_line->para;
	f = npara(a);
	i = o + npara(a).val();
	
	cerr << "FILE: '" << f << "' LINE: " << i << '\n';
	
	akt_line->obc = "";
	akt_line->para = "";
	akt_line->encoded = true;
	
}

void ill_siz_err(void) {
	norm_err("illegal size extension to " + akt_line->obc);
}

void op_rng_err(void) {
	norm_err("operand out of range for " + akt_line->obc);
}

void ill_add_err(void) {
	norm_err("illegal adressing mode for " + akt_line->obc );
}

void fatal_err(const Str & err) {
	set_error("FATAL ERROR: ", err);
}

void insert_imm_val (unsigned long a, const NibStr & ns, bool reloc_demand = false);

void insert_imm_val (unsigned long a, const NibStr & ns, bool reloc_demand) {
	
	if (last_ext_ref.length()) {
		obj.imports.add_tail(Import(a, ns.length(), last_ext_ref, reloc_demand));
	} else {
		if (reloc_demand) {
			obj.relocs.add_tail(a);
		}
	}
	
	obj.body.insert(a, ns);
	
	last_ext_ref = "*";
}

void insert_imm_adr (unsigned long a, const NibStr & ns, bool reloc_demand) {
	
	if (last_ext_ref.length()) {
		obj.imports.add_tail(Import(a, ns.length(), last_ext_ref, reloc_demand));
	} else {
		if (last_exp_had_lbl) {
			obj.relocs.add_tail(a);
		}
	}
	
	obj.body.insert(a, ns);
	
	last_ext_ref = "*";
}


double eval_d(Str & e, int & s);
unsigned long long eval_i(Str & e, int & s);

Symbol * find_label_p(const Str & lname, int & s, Str & err) {
	
	Str l(lname);
	
	if ( tmp_lbl ) {
		if ( l.chr(0) == '.' ) {
			l=last_label+l+".";
		}
	}
	
	AVLItem<Symbol> * p = l_arr.find(Symbol(l));
	
	if (p == 0) {
		err = "undefined label '"+l+"'";
		s = -1;
		return 0;
	} else {
		if ( p->resolved ) {
			if (p->external) {
				if (last_ext_ref.length()) {
					s = -1;
					err = "no (further) external reference allowed here";
					return 0;
				} else {
					last_ext_ref = l;
					p->accessed = true;
					return 0;
				}
			} else {
				p->accessed = true;
				return p;
			}
		} else {
			s = 0;
			return 0;
		}
	}
}

double find_label_d(const Str & lname, int & s, Str & err) {
	Symbol * p = find_label_p(lname, s, err);
	if (!p) return 0;
	if (! p->isfloat) {
		err = "cannot use integer value in floating point expression";
		s = -1;
		return 0;
	}
	return p->fvalue;
}

unsigned long long find_label_i(const Str & lname, int & s, Str & err) {
	Symbol * p = find_label_p(lname, s, err);
	if (!p) return 0;
	if (p->isfloat) {
		err = "cannot use floating point value in integer expression";
		s = -1;
		return 0;
	}
	
	if (! p->numerical) {
		last_exp_had_lbl = true;
	}
	
	return p->ivalue;
}

double use_val_d(Str & e, int & s, Str & err) {
	double x;
	Str a;
	unsigned long i;
	
	for (i = 0; i < e.length(); i++) {
		bool flag = false;
		switch (e.chr(i)) {
		case '+':
		case '-':
		case '*':
		case '/':
		case '\\':
		case '&':
		case '|':
		case '(':
		case ')':
		case ' ':
		case ',':
			flag = true;
			break;
		}
		if (flag) break;
	}
	a = e.left(i);
	e = e.after(i-1);

	x = atof((char *)a);

	return x;
}

unsigned long long use_val_i(Str & e, int & s, Str & err) {
	unsigned long long x;
	Str a;
	unsigned int i;
	
	for (i = 0; i < e.length(); i++) {
		bool flag = false;
		switch (e.chr(i)) {
		case '+':
		case '-':
		case '*':
		case '/':
		case '\\':
		case '&':
		case '|':
		case '(':
		case ')':
		case ' ':
		case ',':
			flag = true;
			break;
		}
		if (flag) break;
	}
	a = e.left(i);
	e = e.after(i-1);

	x = a.vall();

	return x;
}

long big_endian(const char * lword) {
	static int is_big_endian = -1;
	
	if (is_big_endian > 0) {
		return *((long *)lword);
	} else if (is_big_endian == 0 ) {
		return (*lword  & 0xff) | ((*(lword+1) << 8) & 0xff00) |
		   ((*(lword+1) << 16) & 0xff0000) | ((*(lword+1) << 24) & 0xff000000); 
	} else {
		long test = 0;
		*((char *)&test) = 1;
		is_big_endian = (test == 1)? 0 : 1;
		return big_endian(lword);
	}
}

double get_val_d(Str & e, int & s, Str & err) {
	double x;
	Str a;
	
	switch (e.chr(0)) {
	case '0':
	case '1':
	case '2':
	case '3':
	case '4':
	case '5':
	case '6':
	case '7':
	case '8':
	case '9':
		return use_val_d(e,s,err);
	case '$':
		err = "hex numbers for floating-point constants not allowed";
		s = -1;
		x = 0;
		return x;
	case '%':
		err = "bin numbers for floating-point constants not allowed";
		s = -1;
		x = 0;
		return x;
	case 34:
		err = "characters for floating-point constants not allowed";
		s = -1;
		x = 0;
		return x;
	case '(':
		e = e.after(0);
		x = eval_d(e,s);
		return x;
	case '-':
		e = e.after(0);
		x = get_val_d(e,s,err);
		x = -x;
		return x;
	default:
		unsigned int i;
		for (i = 0; i < e.length(); i++) {
			bool flag = false;
			switch (e.chr(i)) {
			case '+':
			case '-':
			case '*':
			case '/':
			case '\\':
			case '&':
			case '|':
			case '(':
			case ')':
				flag = true;
				break;
			}
			if (flag) break;
		}
		a = e.left(i);
		e = e.after(i-1);
		x = find_label_d(a,s,err);
		return x;
	}
}

unsigned long long get_val_i(Str & e, int & s, Str & err) {
	unsigned long long x;
	Str a;
	unsigned long j;
	
	switch (e.chr(0)) {
	case '0':
	case '1':
	case '2':
	case '3':
	case '4':
	case '5':
	case '6':
	case '7':
	case '8':
	case '9':
		return use_val_i(e,s,err);
	case '$':
		e = "0x"+e.after(0);
		return use_val_i(e,s,err);
	case '%':
		e = "0b"+e.after(0);
		return use_val_i(e,s,err);
	case 34:
		j = (e.after(0)).index((char)34) + 1;
		if ( j == (unsigned long)~0 ) {
			err = "missing quotation mark in '"+e+"'";
			s = -1;
			x = 0;
		} else {
			a = e.sub(1,j);
			e = e.after(j);
			if ( a.length() > 4 || a.length()==0 ) {
				err = "operand '"+a+"' out of range";
				s = -1;
				x = 0;
			} else {
				char tmp[4] = { 0,0,0,0 };
				for ( unsigned long i = 0; i < a.length() ; i++) {
					tmp[3-i] = a.chr(a.length()-(i+1));
				}
				x = (unsigned long long) big_endian(tmp);
			}
		}
		return x;
	case '(':
		e = e.after(0);
		x = eval_i(e,s);
		return x;
	case '-':
		e = e.after(0);
		x = get_val_i(e,s,err);
		x = -x;
		return x;
	default:
		unsigned long i;
		for (i = 0; i < e.length(); i++) {
			bool flag = false;
			switch (e.chr(i)) {
			case '+':
			case '-':
			case '*':
			case '/':
			case '\\':
			case '&':
			case '|':
			case '(':
			case ')':
				flag = true;
				break;
			}
			if (flag) break;
		}
		a = e.left(i);
		e = e.after(i-1);
		x = find_label_i(a,s,err);
		// last_exp_had_lbl = true;
		return x;
	}
}


unsigned long long eval_i(Str & e, int & s)	{ // mit s==1
	unsigned long long x;
	unsigned long long y;
	Str err;
	x = 0;
	while (e.length() && s==1) {
		switch (e.chr(0)) {
		case ')':
			e = e.after(0);
			return x;
		case '*':
			e = e.after(0); 
			y = get_val_i(e,s,err);
			x = x * y;
			break;
		case '+':
			e = e.after(0);
			y = get_val_i(e,s,err);
			x = x + y;
			break;
		case '-':
			e = e.after(0);
			y = get_val_i(e,s,err);
			x = x - y;
			break;
		case '&':
			e = e.after(0);
			y = get_val_i(e,s,err);
			x = x & y;
			break;
		case '|':
			e = e.after(0);
			y = get_val_i(e,s,err);
			x = x | y;
			break;
		case '\\':
			e = e.after(0);
			y = get_val_i(e,s,err);
			x = x ^ y;
			break;
		case '/':
			e = e.after(0);
			y = get_val_i(e,s,err);
			if ( y == 0 && s==0 ) {
				err = "division by zero in expression";
				s = 1;
			} else if ( s == -1 || s == 0 ) {
				x = 0;
			} else {
				x = x / y;
			}
			break;
		default:
			x = get_val_i(e,s,err);
		}
	}
	
	if ( s != -1 ) {
		return x;
	} else {
		norm_err(err);
		s = 0;
		return 0;
	}
}

double eval_d(Str & e, int & s)	{ // mit s==1
	double x;
	double y;
	Str err;
	x = 0;
	while (e.length() && s==1) {
		switch (e.chr(0)) {
		case ')':
			e = e.after(0);
			return x;
		case '*':
			e = e.after(0); 
			y = get_val_d(e,s,err);
			x = x * y;
			break;
		case '+':
			e = e.after(0);
			y = get_val_d(e,s,err);
			x = x + y;
			break;
		case '-':
			e = e.after(0);
			y = get_val_d(e,s,err);
			x = x - y;
			break;
		case '&':
			err = "no '&' operator defined for floating point numbers";
			s = 1;
			break;
		case '|':
			err = "no '|' operator defined for floating point numbers";
			s = 1;
			break;
		case '\\':
			err = "no '\\' operator defined for floating point numbers";
			s = 1;
			break;
		case '/':
			e = e.after(0);
			y = get_val_d(e,s,err);
			if ( y == 0 && s==0 ) {
				err = "division by zero in expression";
				s = 1;
			} else if ( s == -1 || s == 0 ) {
				x = 0;
			} else {
				x = x / y;
			}
			break;
		default:
			x = get_val_d(e,s,err);
		}
	}
	
	if ( s != -1 ) {
		return x;
	} else {
		norm_err(err);
		s = 0;
		return 0;
	}
}

int cmp_label( const void * ap, const void * bp) {
	const Symbol * a = (const Symbol *)ap;
	const Symbol * b = (const Symbol *)bp;
	if (a->isfloat) {
		if (b->isfloat) {
			if (a->fvalue <  b->fvalue) return -1;
			if (a->fvalue == b->fvalue) return 0;
			return 1;
		} else {
			return 1;
		}
	} else {
		if (b->isfloat) {
			return -1;
		} else {
			if (a->ivalue <  b->ivalue) return -1;
			if (a->ivalue == b->ivalue) return 0;
			return 1;
		}
	}
}

void unused_labels(void) {
	bool f = true;
	AVLItem<Symbol> * p = l_arr.get_head();
	while (p) {
		if (! p->numerical) {
			if (! p->accessed) {
				if (f) {
					f = false;
					cerr << "following non-numerical labels were never used: \n";
				}
				cerr << p->name << '\n';
			}
		}
		p = l_arr.get_next(p);
	}
	return;
}

int set_label(Symbol & y) {
	int s = 1;
	Str e(akt_line->para);
	e = npara(e);
	unsigned long long x = eval_i(e,s);
	y.isfloat = false;
	switch (s) {
	case 1:
		y.ivalue = x;
		y.resolved = true;
		y.numerical = true;
		break;
	case 0:
	case -1:
		y.ivalue = 0;
	}
	
	return s;
}

void init_lbl(void) {
	if (akt_line->label.length()) {
		AVLItem<Symbol> * y = l_arr.find(Symbol(akt_line->label));
		if (y) {
			if (akt_line->obc == "SET") {
				if ( 1 != set_label(*y)) {
					norm_err("SET cannot resolve reference(s) in '"+akt_line->para+"'");
				}
				akt_line->obc = "";
			} else {
				norm_err("double definition of label '"+akt_line->label+"'");	
			}
		} else {
			AVLItem<Symbol> * p = new AVLItem<Symbol>;
			p->name = akt_line->label;
			p->isfloat = false;
			l_arr.insert(p);
			if (akt_line->label.right(1) == ".") {
				akt_line->label = "";
			}
			if (akt_line->obc == "EQU") {
				p->reference = akt_line;
				p->numerical = true;
			} else if (akt_line->obc == "SET") {
				if ( 1 != set_label(*p)) {
					norm_err("SET cannot resolve reference(s) in '"+akt_line->para+"'");
				}
				akt_line->obc = "";
			} else {
				p->ivalue = adr;
				p->resolved = true;
				p->numerical = false;
			}
		}
	}
}

NibStr & hrval(unsigned long long x, int n) {  // n==0 means 1 nibble

	static NibStr res;
	
	res.clear();

	if (n < 15) {
		if ( x >=  ((unsigned long long)0x10 << (n*4)) ) {
			op_rng_err();
			return res;
		}
	}

	res = NibStr(x, n+1);

	return res;

}


NibStr & rel_jmp(const Str & target, int offset, int nibs) {
	
	static NibStr res;
	static Str t;
	int x;
	int diff;
	
	res.clear();
	t = target;
	
	if ( t.length() ) {
		int s = 1;
		x = (int) eval_i(t,s);
		if ( s==1 ) {
			diff = x-(adr+offset);
			int msn = (diff & (0xf << (nibs*4))) >> (nibs*4);
			if ( (diff > -1 && msn > 7 ) ||
			     (diff < 0  && msn < 8 ) ) {
				op_rng_err();
			} else {
				res = NibStr((unsigned long long)diff, nibs+1);
			}
		}
	} else {
		res = NibStr((unsigned long long)0,2);
	}
	return res;
}

NibStr & fval(double x) {
	static NibStr res(16);
	char * src = DtoR(x);
	
	for (int i = 0; i < 16; i++) {
		res.poke(i, (unsigned long) ((*src++) - '0'), 1);
	}
	
	return res;
}

NibStr & hval(unsigned long long x, int n) {

	static NibStr tmp;
	static NibStr res;
	
	tmp = hrval(x, n);
	res = tmp;
	
	for (unsigned long i = 0; i < res.length(); i++) {
		res.poke(i, tmp.peek(res.length()-(i+1), 1), 1);
	}

	return res;
	
}

NibStr & hgval(unsigned long long x, int n) { // n==0 means 1 nibble

	static NibStr res;
	
	res = hval(x, n);
	
	for (unsigned long i = 0; i < res.length() ; i++) {
		res.poke(i, (unsigned long long) rev_nibs[(int)res.peek(i,1)], 1);
	}

	return res;
}

void get_p1val(int & s, unsigned long long & x) {
	last_ext_ref.clear();
	s = 1;
	static Str e;
	e = p1.right(p1.length()-1);
	x = eval_i(e,s);	
}

void get_p1lbl(int & s, unsigned long long & x) {
	last_exp_had_lbl = false;
	last_ext_ref.clear();
	s = 1;
	Str e(p1);
	x = eval_i(e,s);
}

int sd1_mode(const Str & x, const Str & y) {
	if (x.length() != 1 || y.length() != 1) return -1;
	
	switch (x.chr(0)) {
	case 'a':
		switch (y.chr(0)) {
		case 'c':
			return 6;
		case 'b':
			return 8;
		default:
			return -1;
		}
	case 'b':
		switch (y.chr(0)) {
		case 'a':
			return 4;
		case 'c':
			return 9;
		default:
			return -1;
		}
	case 'c':
		switch( y.chr(0)) {
		case 'b':
			return 5;
		case 'd':
			return 7;
		case 'a':
			return 10;
		default:
			return -1;
		}
	case 'd':
		switch( y.chr(0)) {
		case 'c':
			return 11;
		default:
			return -1;
		}
	}
	return -1;
}

int sd2_mode(const Str & x, const Str & y) {
	if (x.length() != 1 || y.length() != 1) return -1;
	switch (x.chr(0)) {
	case 'a':
		switch( y.chr(0)) {
		case 'c':
			return 2;
		case 'a':
			return 4;
		case 'b':
			return 8;
		default:
			return -1;
		}
	case 'b':
		switch( y.chr(0)) {
		case 'a':
			return 0;
		case 'b':
			return 5;
		case 'c':
			return 9;
		default:
			return -1;
		}
	case 'c':
		switch( y.chr(0)) {
		case 'b':
			return 1;
		case 'd':
			return 3;
		case 'c':
			return 6;
		case 'a':
			return 10;
		default:
			return -1;
		}
	case 'd':
		switch( y.chr(0)) {
		case 'd':
			return 7;
		case 'c':
			return 11;
		default:
			return -1;
		}
	}
	return -1;
}

int sd3_mode(const Str & x, const Str & y) {
	if (x.length() != 1 || y.length() != 1) return -1;
	switch( x.chr(0) ) {
	case 'a':
		switch( y.chr(0) ) {
		case 'c':
			return 2;
		case 'b':
			return 8;
		default:
			return -1;
		}
	case 'b':
		switch( y.chr(0) ) {
		case 'a':
			return 0;
		case 'c':
			return 9;
		default:
			return -1;
		}
	case 'c':
		switch( y.chr(0)) {
		case 'b':
			return 1;
		case 'd':
			return 3;
		case 'a':
			return 10;
		default:
			return -1;
		}
	case 'd':
		switch( y.chr(0)) {
		case 'c':
			return 11;
		default:
			return -1;
		}
	}
	return -1;
}

int sd4_mode(const Str & x, const Str & y) {
	if (x.length() != 1 || y.length() != 1) return -1;

	switch( x.chr(0) ) {
	case 'a':
		switch( y.chr(0)) {
		case 'c':
			return 14;
		default:
			return -1;
		}
	case 'b':
		switch( y.chr(0)) {
		case 'a':
			return 12;
		default:
			return -1;
		}
	case 'c':
		switch( y.chr(0)) {
		case 'b':
			return 13;
		case 'd':
			return 15;
		default:
			return -1;
		}
	case 'd':
		return -1;
	}
	return -1;
}

int sd5_mode(const Str & x) {
	switch( x.chr(0) ) {
	case 'a':
		return 4;
	case 'b':
		return 5;
	case 'c':
		return 6;
	case 'd':
		return 7;
	}
	return -1;
}

int sd6_mode(const Str & x) {
	switch( x.chr(0) ) {
	case 'a':
		return 12;
	case 'b':
		return 13;
	case 'c':
		return 14;
	case 'd':
		return 15;
	}
	return -1;
}

int sd7_mode(const Str & x, const Str & y) {
	switch( x.chr(0) ) {
	case 'a':
		switch( y.chr(0)) {
		case 'c':
			return 10;
		case 'b':
			return 12;
		default:
			return -1;
		}
	case 'b':
		switch( y.chr(0)) {
		case 'a':
			return 8;
		case 'c':
			return 13;
		default:
			return -1;
		}
	case 'c':
		switch( y.chr(0) ) {
		case 'b':
			return 9;
		case 'd':
			return 11;
		case 'a':
			return 14;
		default:
			return -1;
		}
	case 'd':
		switch( y.chr(0)) {
		case 'c':
			return 15;
		default:
			return -1;
		}
	}
	return -1;
}

int sd8_mode(const Str & x, const Str & y) {
	switch(x.chr(0)) {
	case 'a':
		switch( y.chr(0)) {
		case 'c':
			return 2;
		case 'b':
			return 0;
		default:
			return -1;
		}
	case 'b':
		switch( y.chr(0) ) {
		case 'a':
			return 0;
		case 'c':
			return 1;
		default:
			return -1;
		}
	case 'c':
		switch( y.chr(0) ) {
		case 'b':
			return 1;
		case 'd':
			return 3;
		case 'a':
			return 2;
		default:
			return -1;
		}
	case 'd':
		switch( y.chr(0)) {
		case 'c':
			return 3;
		default:
			return -1;
		}
	}
	return -1;
}

int sd9_mode(const Str & x,const Str & y) {
	switch( x.chr(0) ) {
	case 'a':
		switch( y.chr(0) ) {
		case 'b':
			return 4;
		case 'c':
			return 2;
		default:
			return -1;
		}
	case 'b':
		switch( y.chr(0)) {
		case 'a':
			return 0;
		case 'c':
			return 5;
		default:
			return -1;
		}
	case 'c':
		switch( y.chr(0)) {
		case 'b':
			return 1;
		case 'd':
			return 3;
		case 'a':
			return 6;
		default:
			return -1;
		}
	case 'd':
		switch( y.chr(0)) {
		case 'c':
			return 7;
		default:
			return -1;
		}
	}
	return -1;
}

int sd10_mode(const Str & x,const Str & y) {
	switch( x.chr(0) ) {
	case 'a':
		switch( y.chr(0) ) {
		case 'b':
			return 0;
		case 'c':
			return 6;
		default:
			return -1;
		}
	case 'b':
		switch( y.chr(0)) {
		case 'a':
			return 4;
		case 'c':
			return 1;
		default:
			return -1;
		}
	case 'c':
		switch( y.chr(0)) {
		case 'b':
			return 5;
		case 'd':
			return 7;
		case 'a':
			return 2;
		default:
			return -1;
		}
	case 'd':
		switch( y.chr(0) ) {
		case 'c':
			return 3;
		default:
			return -1;
		}
	}
	return -1;
}

int adr_mode_l(Str & t) {

	if (! t.length()) return 0;
	
	static Str p;
	p = t;
	p.to_lower();
	 
	if ( p.length()==1 && p.chr(0) >= 'a' && p.chr(0) < 'e' ) {
		t = p;
		return 1;
	} else if ( p=="d0" || p=="d1" ) {
		t = p;
		return 2;
	} else if ( p=="(d0)" || p=="(d1)" ) {
		t = p;
		return 3;
	} else if ( p.chr(0) == '#' ) {
		return 4;
	} else if ( p.length() == 2 && p >= "r0" && p < "r5" ) {
		t = p;
		return 5;
	} else if ( p=="p" ) {
		t = p;
		return 6;
	} else if ( p== "st" ) {
		t = p;
		return 7;
	} else if ( p=="hst" ) {
		t = p;
		return 8;
	} else if ( p=="in" ) {
		t = p;
		return 9;
	} else if ( p=="out") {
		t = p;
		return 10;
	} else if ( p.left(2) == "c." ) {
		int x = (p.after(1)).val();
		if ( x >= 0 && x <= 15 ) {
			t = p;
			return 11;
		} else {
			return -1;
		}
	} else if ( p== "(a)" ) {
		t = p;
		return 12;
	} else {
		return -1;
	}
}

NibStr & line_nibs(void) {

	static NibStr result;
	result.clear();
	
	static Str obc;
	obc = akt_line->obc;
	static Str para;
	para = akt_line->para;
	static Str a;
	a = para;
	p1 = npara(a);
	p2 = npara(a);
	static Str p3;
	p3 = npara(a);
	int smod = adr_mode_l(p1);
	int dmod = adr_mode_l(p2);
	int alp_ext = akt_line->alp_ext;
	int num_ext = akt_line->num_ext;
	bool cod = false;
	
	if (obc.length() == 0) {
		cod = true;
	}  else if (obc == "MOVE") {
		if (smod == 1 && dmod == 1) {
			int x = sd1_mode(p1,p2);
			if (x >= 0) {
				if (num_ext == 4) {
					result = NibStr((unsigned long) 0xd + (x << 4), 2);
					cod = true;
				} else if (alp_ext >= 0) {
					result = NibStr((unsigned long) 0xa + ((alp_ext+8) << 4) + (x << 8), 3 ); 
					cod = true;
				} else {
					ill_siz_err();
				}
			} else {
				ill_add_err();
			}
		} 	 else if (smod == 7 && p2=="c") {
			if (alp_ext != 3) {
				ill_siz_err();
			} else {
				result = NibStr((unsigned long)0x90 , 2);
				cod = true;
			}
		} else if (p1 == "c" && dmod == 7) {
			if (alp_ext != 3) {
				ill_siz_err();
			} else {
				result = NibStr((unsigned long)0xa0 , 2);
				cod = true;
			}
		} else if ( (p1=="a" || p1=="c") && dmod==2 ) {
			int x = 0;
			if (p1 == "c") x += 4;
			if (p2 == "d1") x += 1;
			if (num_ext == 3 ) x += 8;
			if (num_ext == 4) {
				result = NibStr((unsigned long)0x31 + (x << 8) , 3);				
				cod = true;
			} else {
				ill_siz_err();
			}
		} else if (smod == 3 && (p2=="a" || p2 == "c")) {
			if (num_ext == 4 || num_ext == 1 ) {
				int x = 2;
				if (num_ext == 1) x += 8;
				if (p2 == "c") x += 4;
				if (p1 == "(d1)") x += 1;
				result = NibStr((unsigned long)0x41 + (x << 8) , 3);
				cod = true;
			} else if (alp_ext >= 0) {
				int x = 2;
				if (p2 == "c") x += 4;
				if (p1 == "(d1)") x += 1;
				result = NibStr((unsigned long)0x51 + (x << 8) + (alp_ext << 12), 4);
				cod = true;			
			} else if (num_ext >= 0) {
				int x = 10;
				if (p2 == "c") x += 4;
				if (p1 == "(d1)") x += 1;
				result = NibStr((unsigned long)0x51 + (x << 8) + (num_ext << 12), 4);
				cod = true;
			} else {
				ill_siz_err();
			}
		} else if (dmod == 3 && (p1 == "a" || p1 == "c")) {
			if (num_ext == 4 || num_ext == 1) {
				int x = 0;
				if (num_ext == 1) x += 8;
				if (p1 == "c") x += 4;
				if (p2 == "(d1)") x += 1;
				result = NibStr((unsigned long)0x41 + (x << 8), 3);
				cod = true;
			} else if (alp_ext >= 0) {
				int x = 0;
				if (p1 == "c") x += 4;
				if (p2 == "(d1)") x += 1;
				result = NibStr((unsigned long)0x51 + (x << 8) + (alp_ext << 12), 4);
				cod = true;
			} else if (num_ext >= 0) {
				int x = 8;
				if (p1 == "c") x += 4;
				if (p2 == "(d1)") x += 1;
				result = NibStr((unsigned long)0x51 + (x << 8) + (num_ext << 12), 4);
				cod = true;
			} else {
				ill_siz_err();				
			}
		} else if (smod == 4) {
			if (dmod == 2) {
				if (num_ext == 4) {
					result = NibStr(7);
				} else if (num_ext == 3) {
					result = NibStr(6);
				} else if (num_ext == 1) {
					result = NibStr(4);
				} else if (alp_ext == -2) {
					akt_line->num_ext = 4;
					result = NibStr(7);
					// obj.relocs.add_tail(adr + 2);
				} else {
					ill_siz_err();
				}
			} else if (dmod == 6) {
				if (num_ext == 0) {
					result = NibStr(2);
				} else {
					ill_siz_err();
				}
			} else if (p2 == "c" || p2 == "c.p") {
				if (num_ext >= 0) {
					result = NibStr(num_ext + 3);
				} else if (alp_ext == -2) {
					akt_line->num_ext = 4;
					result = NibStr(7);
					// obj.relocs.add_tail(adr + 2);
				} else {
					ill_siz_err();
				}
			} else if (p2 == "a" || p2 == "a.p") {
				if (num_ext >= 0) {
					result = NibStr(num_ext + 6);
				} else if (alp_ext == -2) {
					akt_line->num_ext = 4;
					result = NibStr(10);
					// obj.relocs.add_tail(adr + 5);
				} else {
					ill_siz_err();
				}
			} else {
				ill_add_err();
			}
		} else if ( (p1 == "a" || p1 == "c") && dmod==5 ) {
			if (num_ext == 15) {
				int x = 0;
				if (p1 == "c") x += 8;
				x += p2.chr(p2.length()-1) - '0';
				result = NibStr((unsigned long)0x01 + (x << 8), 3);
				cod = true;
			} else if (alp_ext > -1 || num_ext == 4) {
				int x = p2.chr(p2.length()-1) - '0';
				if (p1 == "c") x += 8;
				if (num_ext == 4) alp_ext = 15;
				result = NibStr((unsigned long)0xa18 + (alp_ext << 12) + (x << 20), 6);
				cod = true;
			} else {
				ill_siz_err();
			}
		} else if ( (p2 == "a" || p2 == "c") && smod == 5) {
			if (num_ext == 15) {
				int x = 0;
				if (p2 == "c") x += 8;
				x += p1.chr(p1.length()-1) - '0';
				result = NibStr((unsigned long)0x11 + (x << 8), 3);
				cod = true;
			} else if (alp_ext > -1 || num_ext == 4) {
				int x = p1.chr(p1.length()-1) - '0';
				if (p2 == "c") x += 8;
				if (num_ext == 4) alp_ext = 15;
				result = NibStr((unsigned long)0xa18 + (alp_ext << 12) + (1 << 16) + (x << 20), 6);
				cod = true;
			} else {
				ill_siz_err();
			}
		} else if ( smod == 9 && (p2=="a" || p2 == "c") ) {
			if (num_ext != 3) {
				ill_siz_err();
			} else {
				int x = 2;
				if (p2=="c") x += 1;
				result = NibStr((unsigned long)0x08 + (x << 8), 3);
				cod = true;
			}
		} else if (dmod==10 && p1 == "c") {
			if (num_ext == 2) {
				result = NibStr((unsigned long)0x108 , 3);
				cod = true;
			} else if (alp_ext == 4) {
				result = NibStr((unsigned long)0x008 , 3);
				cod = true;
			} else {
				ill_siz_err();
			}
		} else if (p1 == "p" && dmod == 11) {
			if (num_ext != 0) {
				ill_siz_err();
			} else {
				int x = (p2.after(1)).val();
				result = NibStr((unsigned long)0xc08 + (x << 12) , 4);
				cod = true;
			}
		} else if ( p2=="p" && smod==11 ) {
			if ( num_ext != 0 ) {
				ill_siz_err();
			} else {
				int x = (p1.after(1)).val();
				result = NibStr((unsigned long)0xd08 + (x << 12), 4);
				cod = true;
			}
		} else if ( p1=="pc" && (p2=="a" || p2=="c") ) {
			if ( num_ext == 4 ) {
				cod = true;
				if ( p2=="a" ) {
					result = NibStr((unsigned long)0x4b18 , 4);
				} else {
					result = NibStr((unsigned long)0x5b18 , 4);
				}
			} else {
				ill_siz_err();
			}
		} else {
			ill_add_err();
		}
	} 	else if ( obc == "EXG" ) {
		if ( (smod == 5 && dmod != 5) || (smod != 5 && dmod == 5) ) {
			if ( smod == 5 ) {
				int tmp = dmod;
				dmod = smod;
				smod = tmp;
				
				Str t = p2;
				p2 = p1;
				p1 = t;
			}
			if ( p1=="c" || p1=="a" ) {
				if ( num_ext == 15 ) {
					int x = 0;
					if ( p1=="c" ) {
						x += 8;
					}
					x += p2.chr(p2.length()-1) - '0';
					result = NibStr((unsigned long)0x21 + (x << 8) , 3);
					cod = true;
				} else if ( alp_ext > -1 || num_ext == 4 ) {
					int x = p2.chr(p2.length()-1) - '0';
					if ( p1=="c" ) {
						x += 8;
					}
					if ( num_ext == 4 ) {
						alp_ext = 15;
					}
					result = NibStr((unsigned long)0xa18+(alp_ext << 12)+(2 << 16)+(x << 20), 6);
					cod = true;
				} else {
					ill_siz_err();
				}
			} else {
				ill_add_err();
			}
		} else if ( (smod==2 && dmod != 2) || (smod != 2 && dmod == 2)) {
			if ( num_ext == 4 || num_ext == 3 ) {
				if ( smod == 2 ) {
					int tmp = dmod;
					dmod = smod;
					smod = tmp;
					
					Str t = p1;
					p1 = p2;
					p2 = t;	
				}
				if ( p1 == "a" || p1 == "c" ) {
					int x = 2;
					if ( p1 == "c" ) {
						x += 4;
					}
					if ( p2 == "d1" ) {
						x += 1;
					}
					if ( num_ext==3 ) {
						x += 8;
					}
					result = NibStr((unsigned long)0x31 + (x << 8) , 3);
					cod = true;
				} else {
					ill_add_err();
				}
			} else {
				ill_siz_err();
			}
		} else if ( smod==1 && dmod==1 ) {
			if ( p1 > p2 ) {
				Str t = p2;
				p2 = p1;
				p1 = t;
			}
			int x;
			if ( p1=="a" && p2=="b" ) {
				x=12;
			} else if ( p1=="b" && p2=="c" ) {
				x=13;
			} else if ( p1=="a" && p2=="c" ) {
				x=14;
			} else if ( p1=="c" && p2=="d" ) {
				x=15;
			} else {
				ill_add_err();
				x=0;
			}
			if ( x > 0 ) {
				if ( num_ext == 4 ) {
					result = NibStr((unsigned long)0xd + (x << 4) , 2);
					cod = true;
				} else if ( alp_ext >= 0 ) {
					result = NibStr((unsigned long)0xa + ((alp_ext+8) << 4) + (x << 8) , 3);
					cod = true;
				} else {
					ill_siz_err();
				}
			}
		} else if ( (smod==11) ^ (dmod==11) ) {
			if ( smod==11 ) {
				int tmp = dmod;
				dmod = smod;
				smod = tmp;
				
				Str t = p2;
				p2 = p1;
				p1 = t;
			}
			if ( smod==6 ) { 
				int x = (p2.after(1)).val();
				result = NibStr((unsigned long)0xf08 + (x << 12) , 4);
				cod = true;
			} else {
				ill_add_err();
			}
		} else if ( (p1=="pc") ^ (p2=="pc") ) {
			if ( num_ext == 4 ) {
				if ( p1 == "pc" ) {
					Str t = p2;
					p2 = p1;
					p1 = t;
				}
				if ( p1=="a" ) {
					result = NibStr((unsigned long)0x6b18 , 4);
					cod = true;
				} else if ( p1=="c" ) {
					result = NibStr((unsigned long)0x7b18 , 4);
					cod = true;
				} else {
					ill_add_err();
				}
			} else {
				ill_siz_err();
			}
		} else {
			ill_add_err();
		}
	} else if ( obc == "ADD" ) {
		if ( smod==4 && dmod==2 ) {
			result = NibStr(3);
		} else if ( smod==4 && dmod==1 ) {
			if ( alp_ext > -1 || num_ext == 4 ) {
				result = NibStr(6);
			} else {
				ill_siz_err();
			}
		} else if ( smod==1 && dmod==1 ) {
			int x = sd2_mode(p1,p2);
			if ( x >= 0 ) {
				if ( num_ext == 4 ) {
					result = NibStr((unsigned long)0xc + (x << 4) , 2);
					cod = true;
				} else if ( alp_ext >= 0 ) {
					result = NibStr((unsigned long)0xa + (alp_ext << 4) + (x << 8) , 3);
					cod = true;
				} else {
					ill_siz_err();
				}
			} else {
				ill_add_err();
			}
		} else if ( p1=="p+1" && p2=="c" ) {
			if ( num_ext==4 ) {
				result = NibStr((unsigned long)0x908 , 3);
				cod = true;
			} else {
				ill_siz_err();
			}
		} else {
			ill_add_err();
		}
	} else if ( obc == "SUB" ) {
		if ( smod==1 && dmod==1 ) {
			int x = sd3_mode(p1,p2);
			if ( x >= 0 ) {
				if ( num_ext==4 ) {
					result = NibStr((unsigned long)0xe + (x << 4) , 2);
					cod = true;
				} else if ( alp_ext >= 0 ) {
					result = NibStr((unsigned long)0xb + (alp_ext << 4) + (x << 8) , 3);
					cod = true;
				} else {
					ill_siz_err();
				}
			} else {
				ill_add_err();
			}
		} else if ( smod==4 && dmod==2 ) {
			result = NibStr(3);
		} else if ( smod==4 && dmod==1 ) {
			if ( alp_ext > -1 || num_ext == 4 ) {
				result = NibStr(6);
			} else {
				ill_siz_err();
			}
		} else {
			ill_add_err();
		}
	}  else if ( obc == "SUBR" ) {
		if ( smod==1 && dmod==1 ) {
			int x = sd4_mode(p1,p2);
			if ( x >= 0 ) {
				if ( num_ext == 4) {
					result = NibStr((unsigned long)0xe + (x << 4) , 2);
					cod = true;
				} else if ( alp_ext >= 0 ) {
					result = NibStr((unsigned long)0xb + (alp_ext << 4) + (x << 8) , 3);
					cod = true;
				} else {
					ill_siz_err();
				}
			} else {
				ill_add_err();
			}
		} else {
			ill_add_err();
		}
	} else if ( obc == "INC" ) {
		if ( smod==1 && dmod==0 ) {
			if ( num_ext==4 ) {
				result = NibStr((unsigned long)0xe + (sd5_mode(p1) << 4), 2);
				cod = true;
			} else if ( alp_ext >= 0 ) {
				result = NibStr((unsigned long)0xb + (alp_ext << 4) + (sd5_mode(p1) << 8), 3);
				cod = true;
			} else {
				ill_siz_err();
			}
		} else if ( smod==6 && dmod==0 ) {
			if ( num_ext==0 ) {
				result = NibStr((unsigned long)0xc0 , 2);
				cod = true;
			} else {
				ill_siz_err();
			}
		} else if ( smod==2 && dmod==0 ) {
			if ( num_ext == 4 ) {
				int x = 6;
				if ( p1 == "d1") {
					x += 1;
				}
				result = NibStr((unsigned long)0x1 + (x << 4)   , 3);
				cod = true;
			} else {
				ill_siz_err();
			}
		} else {
			ill_add_err();
		}
	} else if ( obc == "DEC" ) {
		if ( smod==1 && dmod==0 ) {
			if ( num_ext==4 ) {
				result = NibStr((unsigned long)0xc + (sd6_mode(p1) << 4), 2);
				cod = true;
			} else if ( alp_ext >= 0 ) {
				result = NibStr((unsigned long)0xa + (alp_ext << 4) + (sd6_mode(p1) << 8) , 3);
				cod = true;
			} else {
				ill_siz_err();
			}
		} else if ( smod == 6 && dmod == 0 ) {
			if ( num_ext==0 ) {
				result = NibStr((unsigned long)0xd0 , 2);
				cod = true;
			} else {
				ill_siz_err();
			}
		} else if ( smod == 2 && dmod == 0 ) {
			if ( num_ext==4 ) {
				int x = 8;
				if ( p1=="d1" ) {
					x += 4;
				}
				result = NibStr((unsigned long)0x1 + (x << 4)    , 3);
				cod = true;
			} else {
				ill_siz_err();
			}
		} else {
			ill_add_err();
		}
	} else if ( obc == "OR" ) {
		if ( smod==1 && dmod==1 ) {
			int x = sd7_mode(p1,p2);
			if ( num_ext==4 ) {
				result = NibStr((unsigned long)0xfe0 + (x << 12) , 4);
				cod = true;
			} else if ( alp_ext >= 0 ) {
				result = NibStr((unsigned long)0xe0 + (alp_ext << 8) + (x << 12) , 4);
				cod = true;
			} else {
				ill_siz_err();
			}
		} else {
			ill_add_err();
		}
	} else if ( obc == "AND" ) {
		if ( smod==1 && dmod==1 ) {
			int x = sd7_mode(p1,p2) - 8;
			if ( x >= 0 ) {
				if ( num_ext==4 ) {
					result = NibStr((unsigned long)0xfe0 + (x << 12) , 4);
					cod = true;
				} else if ( alp_ext >= 0 ) {
					result = NibStr((unsigned long)0xe0 + (alp_ext << 8) + (x << 12) , 4);
					cod = true;
				} else {
					ill_siz_err();
				}
			} else {
				ill_add_err();
			}
		} else {
			ill_add_err();
		}
	} else if ( obc == "CLR" ) {
		if ( dmod==0 ) {
			if ( smod == 7) {
				if ( num_ext == 2 ) {
					result = NibStr((unsigned long)0x80 , 2);
					cod = true;
				} else {
					ill_siz_err();
				}
			} else if ( smod==1 ) {
				int x = sd5_mode(p1) - 4;
				if ( num_ext == 4 ) {
					result = NibStr((unsigned long)0xd + (x << 4), 2);
					cod = true;
				} else if ( alp_ext >= 0 ) {
					result = NibStr((unsigned long)0xa + ((alp_ext+8) << 4) + (x << 8), 3);
					cod = true;
				} else {
					ill_siz_err();
				}
			} else {
				ill_add_err();
			}
		} else if ( dmod==8 && smod==4 ) {
			result = NibStr(3);
		} else {
			ill_add_err();
		}
	} else if ( obc == "NEG" ) {
		if ( smod==1 && dmod==0 ) {
			int x = sd5_mode(p1) + 4;
			if ( num_ext == 4 ) {
				result = NibStr((unsigned long)0xf + (x << 4) , 2);
				cod = true;
			} else if ( alp_ext >= 0 ) {
				result = NibStr((unsigned long)0xb + ((alp_ext+8) << 4) + (x << 8) , 3);
				cod = true;
			} else {
				ill_siz_err();
			}
		} else {
			ill_add_err();
		}
	} else if ( obc == "NOT" ) {
		if ( smod==1 && dmod==0 ) {
			int x = sd5_mode(p1) + 8;
			if ( num_ext == 4) {
				result = NibStr((unsigned long)0xf + (x << 4), 2);
				cod = true;
			} else if ( alp_ext >= 0 ) {
				result = NibStr((unsigned long)0xb + ((alp_ext+8) << 4) + (x << 8) , 3);
				cod = true;
			} else {
				ill_siz_err();
			}
		} else {
			ill_add_err();
		}
	} else if ( obc == "LSL" ) {
		if ( p1=="#4" && dmod==1 ) {
			int x = sd5_mode(p2) - 4;
			if ( num_ext == 4 ) {
				result = NibStr((unsigned long)0xf + (x << 4), 2);
				cod = true;
			} else if ( alp_ext >= 0 ) {
				result = NibStr((unsigned long)0xb + ((alp_ext+8) << 4) + (x << 8) , 3);
				cod = true;
			} else {
				ill_siz_err();
			}
		} else if ( p1 == "#1" && dmod==1 ) {
			int x = sd5_mode(p2);
			if ( num_ext==4 ) {
				result = NibStr((unsigned long)0xc + (x << 4) , 2);
				cod = true;
			} else if ( alp_ext >= 0 ) {
				result = NibStr((unsigned long)0xa + (alp_ext << 4) + (x << 8) , 3);
				cod = true;
			} else {
				ill_siz_err();
			}
		} else {
			ill_add_err();
		}
	} else if ( obc == "LSR" ) {
		if ( p1=="#4" && dmod==1 ) {
			int x = sd5_mode(p2);
			if ( num_ext == 4) {
				result = NibStr((unsigned long)0xf + (x << 4) , 2);
				cod = true;
			} else if ( alp_ext >= 0 ) {
				result = NibStr((unsigned long)0xb + ((alp_ext+8) << 4) + (x << 8) , 3);
				cod = true;
			} else {
				ill_siz_err();
			}
		} else if ( p1=="#1" && dmod==1 ) {
			int x = sd5_mode(p2) + 8;
			if ( num_ext==15 || (num_ext == -1 && alp_ext == -1)) {
				result = NibStr((unsigned long)0x18 + (x << 8) , 3);
				cod = true;
			} else if ( num_ext==4 || alp_ext > -1 ) {
				if ( num_ext==4 ) {
					alp_ext = 15;
				}
				x -= 12;
				result = NibStr((unsigned long)0x918 + (alp_ext << 12) + (x << 16) , 5);
				cod = true;
			} else {
				ill_siz_err();
			}
		} else {
			ill_add_err();
		}
	} else if ( obc == "ROL") {
		if ( p1=="#4" && dmod==1 ) {
			int x = sd5_mode(p2) - 4;
			if ( num_ext==15 ) {
				result = NibStr((unsigned long)0x18 + (x << 8) , 3);
				cod = true;
			} else {
				ill_siz_err();
			}
		} else {
			ill_add_err();
		}
	} else if ( obc == "ROR" ) {
		if ( p1=="#4" && dmod==1 ) {
			int x = sd5_mode(p2);
			if ( num_ext == 15 ) {
				result = NibStr((unsigned long)0x18 + (x << 8) , 3);
				cod = true;
			} else {
				ill_siz_err();
			}
		} else {
			ill_add_err();
		}
	} else if ( obc == "BCLR") {
		if ( smod==4 && (p2=="c" || p2=="a") ) {
			result = NibStr(5);
		} else if ( smod==4 && dmod==7 ) {
			result = NibStr(3);
		} else {
			ill_add_err();
		}
	} else if ( obc == "BSET" ) {
		if ( smod==4 && (p2=="c" || p2=="a") ) {
			result = NibStr(5);
		} else if ( smod==4 && dmod==7 ) {
			result = NibStr(3);
		} else {
			ill_add_err();
		}
	} else if ( obc == "BCS" || obc == "BCC" ) {
		if ( smod == -1 && dmod==0 ) {
			if ( num_ext==1 || num_ext == -1 ) {
				result = NibStr(3);
			} else {
				ill_siz_err();
			}
		} else {
			ill_add_err();
		}
	} else if ( obc == "RTCC" ) {
		result = NibStr((unsigned long)0x005 , 3);
		cod = true;
	} else if ( obc == "RTCS" ) {
		result = NibStr((unsigned long)0x004 , 3);
		cod = true;
	} else if ( obc == "BRA" ) {
		if ( smod == -1 && dmod==0 ) {
			if ( num_ext==2 || num_ext == -1 ) {
				result = NibStr(4);
			} else if ( num_ext==3 ) {
				result = NibStr(6);
			} else {
				ill_siz_err();
			}
		} else {
			ill_add_err();
		}
	} else if ( obc == "BSR" ) {
		if ( smod==-1 && dmod==0 ) {
			if ( num_ext==2 || num_ext == -1 ) {
				result = NibStr(4);
			} else if ( num_ext==3 ) {
				result = NibStr(6);
			} else {
				ill_siz_err();
			}
		} else {
			ill_add_err();
		}
	} else if ( obc == "JMP" ) {
		if ( smod==-1 && dmod==0 ) {
			if ( num_ext == -1 ) {
				result = NibStr(7);
			} else {
				ill_siz_err();
			}
		} else if ( smod==12 && dmod==0 ) {
			if ( num_ext == -1 ) {
				result = NibStr((unsigned long)0xc808, 4);
				cod = true;
			} else {
				ill_siz_err();
			}
		} else if ( p1=="a" || p1=="c" ) {
			if ( num_ext == 4 || num_ext == -1) {
				cod = true;
				if ( p1 == "a") {
					result = NibStr((unsigned long)0x2b18, 4);
				} else {
					result = NibStr((unsigned long)0x3b18, 4);
				}
			} else {
				ill_siz_err();
			}
		} else {
			ill_add_err();
		}
	} else if ( obc == "JSR" ) {
		if ( smod == -1 && dmod==0 ) {
			if ( num_ext == -1 ) {
				result = NibStr(7);
			} else {
				ill_siz_err();
			}
		} else {
			ill_add_err();
		}
	} else if ( obc == "BEQ" || obc == "RTEQ" ) {
		int ddmod = adr_mode_l(p3);
		if ( (obc == "BEQ" && ddmod == -1) || (obc == "RTEQ" && ddmod == 0) ) {
			if ( smod==4 && dmod==8 ) {
				if ( num_ext==0 || num_ext == -1 ) {
					result = NibStr(5);
				} else {
					ill_siz_err();
				}
			} else if ( smod==4 && dmod==6) {
				if ( num_ext == 0 || num_ext == -1 ) {
					result = NibStr(5);
				} else {
					ill_siz_err();
				}
			} else if ( smod==1 && dmod==1 ) {
				if ( sd8_mode(p1,p2) >= 0) {
					if ( num_ext==4 || alp_ext >= 0) {
						result = NibStr(5);
					} else {
						ill_siz_err();
					}
				} else {
					ill_add_err();
				}
			} else if ( smod==1 && p2=="0" ) {
				if ( num_ext==4 || alp_ext >= 0) {
					result = NibStr(5);
				} else {
					ill_siz_err();
				}
			} else {
				ill_add_err();
			}
		} else {
			ill_add_err();
		}
	} else if ( obc == "BNE" || obc == "RTNE" ) {
		int ddmod = adr_mode_l(p3);
		if ( (obc == "BNE" && ddmod == -1) || (obc == "RTNE" && ddmod == 0) ) {
			if ( smod==4 && dmod==6 ) {
				if ( num_ext==0 || num_ext == -1 ) {
					result = NibStr(5);
				} else {
					ill_siz_err();
				}
			} else if ( smod==1 && dmod==1 ) {
				if ( sd8_mode(p1,p2) >= 0 ) { 
					if ( num_ext==4 || alp_ext >= 0) {
						result = NibStr(5);
					} else {
						ill_siz_err();
					}
				} else {
					ill_add_err();
				}
			} else if ( smod==1 && p2=="0" ) {
				if ( num_ext==4 || alp_ext>=0 ) {
					result = NibStr(5);
				} else {
					ill_siz_err();
				}
			} else {
				ill_add_err();
			}
		} else {
			ill_add_err();
		}
	} else if ( obc == "BLT" || obc == "RTLT" ) {
		int ddmod = adr_mode_l(p3);
		if ( (obc == "BLT" && ddmod == -1) || (obc == "RTLT" && ddmod == 0) ) {
			if ( smod==1 && dmod==1 ) {
				if ( sd9_mode(p1,p2) >= 0 ) {
					if ( num_ext==4 || alp_ext >= 0 ) {
						result = NibStr(5);
					} else {
						ill_siz_err();
					}
				} else {
					ill_add_err();
				}
			} else {
				ill_add_err();
			}
		} else {
			ill_add_err();
		}
	} else if ( obc == "BLE" || obc == "RTLE" ) {
		int ddmod = adr_mode_l(p3);
		if ( (obc == "BLE" && ddmod == -1) || (obc == "RTLE" && ddmod == 0) ) {
			if ( smod==1 && dmod==1 ) {
				if ( sd9_mode(p1,p2) >= 0 ) {
					if ( num_ext==4 || alp_ext >= 0 ) {
						result = NibStr(5);
					} else {
						ill_siz_err();
					}
				} else {
					ill_add_err();
				}
			} else {
				ill_add_err();
			}
		} else {
			ill_add_err();
		}
	} else if ( obc == "BGT" || obc == "RTGT" ) {
		int ddmod = adr_mode_l(p3);
		if ( (obc == "BGT" && ddmod == -1) || (obc == "RTGT" && ddmod ==0) ) {
			if ( smod==1 && dmod==1 ) {
				if ( sd10_mode(p1,p2) >= 0 ) {
					if ( num_ext==4 || alp_ext >= 0) {
						result = NibStr(5);
					} else {
						ill_siz_err();
					}
				} else {
					ill_add_err();
				}
			} else {
				ill_add_err();
			}
		} else {
			ill_add_err();
		}
	} else if ( obc == "BGE" || obc == "RTGE" ) {
		int ddmod = adr_mode_l(p3);
		if ( (obc == "BGE" && ddmod == -1) || (obc == "RTGE" && ddmod == 0) ) {
			if ( smod==1 && dmod==1 ) {
				if ( sd10_mode(p1,p2) >= 0) {
					if ( num_ext==4 || alp_ext >= 0 ) {
						result = NibStr(5);
					} else {
						ill_siz_err();
					}
				} else {
					ill_add_err();
				}
			} else {
				ill_add_err();
			}
		} else {
			ill_add_err();
		}
	} else if ( obc == "BBC" || obc == "RTBC" ) {
		if ( num_ext == -1 ) {
			int ddmod = adr_mode_l(p3);
			if ( (obc == "BBC" && ddmod == -1) || (obc == "RTBC" && ddmod == 0) ) {
				if ( smod==4 && dmod==7 ) {
					result = NibStr(5);
				} else if ( smod==4 && (p2=="c" || p2=="a") ) {
					result = NibStr(7);
				} else {
					ill_add_err();
				}
			} else {
				ill_add_err();
			}
		} else {
			ill_siz_err();
		}
	} else if ( obc == "BBS" || obc == "RTBS" ) {
		if ( num_ext == -1 ) {
			int ddmod = adr_mode_l(p3);
			if ( (obc == "BBS" && ddmod == -1) || (obc == "RTBS" && ddmod == 0) ) {
				if ( smod==4 && dmod==7 ) {
					result = NibStr(5);
				} else if ( smod==4 && (p2=="c" || p2=="a") ) {
					result = NibStr(7);
				} else {
					ill_add_err();
				}
			} else {
				ill_add_err();
			}
		} else {
			ill_siz_err();
		}
	} else if ( smod == 0 && dmod==0 ) {
		if ( obc == "RTNSXM" ) {
			result = NibStr((unsigned long)0x00 , 2);
			cod = true;
		} else if ( obc == "RTN" ) {
			result = NibStr((unsigned long)0x10 , 2);
			cod = true;
		} else if ( obc == "RTNSC" ) {
			result = NibStr((unsigned long)0x20 , 2);
			cod = true;
		} else if ( obc == "RTNCC" ) {
			result = NibStr((unsigned long)0x30 , 2);
			cod = true;
		} else if ( obc == "SETHEX" ) {
			result = NibStr((unsigned long)0x40 , 2);
			cod = true;
		} else if ( obc == "SETDEC" ) {
			result = NibStr((unsigned long)0x50 , 2);
			cod = true;
		} else if ( obc == "PUSH" ) {
			result = NibStr((unsigned long)0x60 , 2);
			cod = true;
		} else if ( obc == "POP" ) {
			result = NibStr((unsigned long)0x70 , 2);
			cod = true;
		} else if ( obc == "NOP4" ) {
			result = NibStr((unsigned long)0x0036 , 4);
			cod = true;
		} else if ( obc == "UNCNFG" ) {
			result = NibStr((unsigned long)0x408 , 3);
			cod = true;
		} else if ( obc == "CONFIG" ) {
			result = NibStr((unsigned long)0x508 , 3);
			cod = true;
		} else if ( obc == "C=ID" ) {
			result = NibStr((unsigned long)0x608 , 3);
			cod = true;
		} else if ( obc == "SHUTDN" ) {
			result = NibStr((unsigned long)0x708 , 3);
			cod = true;
		} else if ( obc == "INTON" ) {
			result = NibStr((unsigned long)0x0808 , 4);
			cod = true;
		} else if ( obc == "RSI" ) {
			result = NibStr((unsigned long)0x01808 , 5);
			cod = true;
		} else if ( obc == "RTI" ) {
			result = NibStr((unsigned long)0xf0 , 2);
			cod = true;
		} else if ( obc == "BUSCD" ) {
			result = NibStr((unsigned long)0xe808 , 4);
			cod = true;
		} else if ( obc == "INTOFF" ) {
			result = NibStr((unsigned long)0xf808 , 4);
			cod = true;
		} else if ( obc == "RESET" ) {
			result = NibStr((unsigned long)0xa08 , 3);
			cod = true;
		} else if ( obc == "BUSCC" ) {
			result = NibStr((unsigned long)0xb08 , 3);
			cod = true;
		} else if ( obc == "SREQ?" ) {
			result = NibStr((unsigned long)0xe08 , 3);
			cod = true;
		} else if ( obc == "INCLUDE" ) {
			cod = true;
		} else if ( obc == "RELTAB" ) {
			result = NibStr(obj.relocs.length() * 5 + 5);
			unsigned long offset = 0;
			ListItem<Reloc> * p = obj.relocs.get_head();
			while (p) {
					result.poke(offset , p->offset, 5);
					offset += 5;
					p = p->get_next();
			}
			result.poke( offset , (unsigned long)0, 5);
			static bool relwarn = true;
			if (relwarn) {
				relwarn = false;
				cerr << "WARNING: RELTAB pseudo-op used, relocation table\n"
				        "         is dumped & cleared.\n";
			}
			obj.relocs.clear();
			cod = true;
		} else {
			norm_err("unknown opcode '"+obc+"'");
		}
	} else if ( obc == "DC" || obc == "DCR" || obc == "DCG" ) {
		if ( alp_ext == -2) num_ext = akt_line->num_ext = 4;
		if ( num_ext >= 0 ) {
			int i = nrof_paras(para);
			result = NibStr(i*(num_ext+1));
		} else {
			ill_siz_err();
		}
	} else if ( obc == "DCF" ) {
		int i = nrof_paras(para);
		result = NibStr(i*16);
	} else if ( obc == "TEXT" || obc == "TEXTR") {
		if ( num_ext == -1 ) {
			if ( p1.chr(0) == 34 && p1.chr(p1.length()-1) == 34 ) {
				Str a = p1.sub(1,p1.length()-1);
				a.implode_escape_sequences();
				result = NibStr(a.length() * 2);
				cod = true;
				bool rflag = false;
				if ( obc == "TEXTR" ) {
					rflag = true;
				}
				const char * c = (char *)a;
				for (unsigned long i=0; i < a.length(); i++) {
					char z = *c++;
					if (!rflag) z = ((z & 0xf) << 4) | ((z & 0xf0) >> 4);
					result.poke(i*2, (unsigned long)z, 2);
				}
			} else {
				norm_err("missing quotation mark in '"+p1+"'");
			}
		} else {
			ill_siz_err();
		}
	} else if ( obc == "INCLUDE" ) {
		cod = true;
	} else if ( obc == "AKTFILE" ) {
		cod = true;
	} else if ( obc == "EQU" ) {
		cod = true;
	} else if ( obc == "XDEF" ) {
		if (exe_flag) {
			norm_err("XDEF pseudo-op ignored due to '-exe' switch");
			cod = true;
		}
	} else if ( obc == "XREF" ) {
		if (exe_flag) {
			norm_err("XREF pseudo-op ignored due to '-exe' switch");
			cod = true;
		} 
	} else {
		norm_err("unknown opcode '"+obc +"'");
		cod = true;
	}
	
	akt_line->binlen = result.length();
	
	if ( cod ) {
		akt_line->encoded = true;
//		akt_line->para = "";
//		akt_line->obc = obc; 
	}
	return result;
}

void line_nibs2(void) {
	int s;
	unsigned long long x;
	int y;
	
	if ( ! akt_line->encoded ) {
		static Str obc;
		obc = akt_line->obc;
		static Str para;
		para = akt_line->para;
		static Str a;
		a = para;
		p1 = npara(a);
		p2 = npara(a);
		static Str p3;
		p3 = npara(a);
		int smod = adr_mode_l(p1);
		int dmod = adr_mode_l(p2);
		int num_ext = akt_line->num_ext;
		int alp_ext = akt_line->alp_ext;
		
		if ( obc == "MOVE" ) {
			get_p1val(s,x);
			if ( s==1 ) {
				if ( dmod==2 ) {
					y = 9;
					if ( p2=="d1" ) {
						y += 4;
					}
					if ( num_ext == 4 ) {
						y += 2;
					} else if ( num_ext==3 ) {
						y += 1;
					}
					obj.body.poke(  adr,  (unsigned long)0x1 + (y << 4), 2);
					insert_imm_val(adr+2, hrval(x,num_ext), (alp_ext == -2));
				} else if ( dmod == 6 ) {
					obj.body.poke( adr, (unsigned long)0x2, 1);
					insert_imm_val( adr+1, hrval(x,0));
				} else if ( p2 == "c" || p2 == "c.p" ) {
					obj.body.poke( adr, (unsigned long)0x3 + (num_ext << 4), 2);
					insert_imm_val( adr+2, hrval(x,num_ext), (alp_ext == -2));
				} else if ( p2 == "a" || p2 == "a.p" ) {
					obj.body.poke( adr, (unsigned long)0x2808 + (num_ext << 16), 5);
					insert_imm_val( adr+5, hrval(x,num_ext), (alp_ext == -2));
				} else {
					norm_err("internal error with opcode '"+obc+"', please report this bug.");
				}
			}
		} else if ( obc == "ADD" ) {
			if ( dmod == 2 ) {
				get_p1val(s,x);
				x--;
				y = 6;
				if ( p2 == "d1" ) {
					y += 1;
				}
				obj.body.poke( adr, (unsigned long)0x1 + (y << 4), 2);
				insert_imm_val( adr+2, hrval(x,0));
			} else {
				get_p1val(s,x);
				int w = (int) x;
				w--;
				if ( w < 16 && w > -1) {
					if ( num_ext == 4 ) {
						alp_ext = 15;
					}
					obj.body.poke(adr, (unsigned long)0x818+(alp_ext << 12) +
					               ((sd5_mode(p2)-4) << 16), 5); 
					insert_imm_val( adr+5, hrval(w,0));
				} else {
					op_rng_err();
				}
			}
		} else if ( obc == "SUB" ) {
			if ( dmod == 2 ) {
				get_p1val(s,x);
				x--;
				y = 8;
				if ( p2=="d1" ) {
					y += 4;
				}
				obj.body.poke( adr, (unsigned long)0x1 + (y << 4), 2);
				insert_imm_val(adr+2, hrval(x,0));
			} else {
				get_p1val(s,x);
				int w = (int) x;
				w--;
				if ( w < 16 && w > -1 ) {
					if ( num_ext == 4 ) {
						alp_ext = 15;
					}
					obj.body.poke(adr, (unsigned long)0x818+ (alp_ext << 12) +
					               ((sd5_mode(p2)+4) << 16), 5);
					insert_imm_val(adr+5, hrval(w,0));
				} else {
					op_rng_err();
				}
			}
		} else if ( obc == "CLR" ) {
			get_p1val(s,x);
			obj.body.poke( adr, (unsigned long)0x28, 2);
			insert_imm_val( adr+2, hrval(x,0));
		} else if ( obc == "BCLR" ) {
			get_p1val(s,x);
			if ( p2 == "c") {
				obj.body.poke( adr, (unsigned long)0x8808, 4);
				insert_imm_val( adr+4, hrval(x,0));
			} else if ( p2=="a" ) {
				obj.body.poke( adr, (unsigned long)0x4808, 4);
				insert_imm_val( adr+4, hrval(x,0));
			} else if ( dmod==7 ) {
				obj.body.poke( adr, (unsigned long)0x48, 2);
				insert_imm_val( adr+2, hrval(x,0));
			} else {
				norm_err("internal error with opcode '"+obc+"', please report this bug.");
			}
		} else if ( obc == "BSET" ) {
			get_p1val(s,x);
			if ( p2 == "c" ) {
				obj.body.poke( adr, (unsigned long)0x9808, 4);
				insert_imm_val( adr+4, hrval(x,0));
			} else if ( p2 == "a" ) {
				obj.body.poke( adr, (unsigned long)0x5808, 4);
				insert_imm_val(adr+4, hrval(x,0));
			} else if ( dmod==7 ) {
				obj.body.poke( adr, (unsigned long)0x58, 2);
				insert_imm_val( adr+2, hrval(x,0));
			} else {
				norm_err("internal error with opcode '"+obc+"', please report this bug.");
			}
		} else if ( obc == "BCS" || obc == "BCC" ) {
			if ( obc == "BCC" ) {
				obj.body.poke( adr, (unsigned long)0x5, 1);
				obj.body.insert( adr+1, rel_jmp(p1,1,1));
			} else if ( obc == "BCS" ) {
				obj.body.poke( adr, (unsigned long)0x4, 1);
				obj.body.insert(adr+1, rel_jmp(p1,1,1));
			}
		} else if ( obc == "BRA" ) {
			if ( num_ext==2 || num_ext == -1 ) {
				obj.body.poke( adr, (unsigned long)0x6, 1);
				obj.body.insert( adr+1, rel_jmp(p1,1,2));
			} else if ( num_ext==3 ) {
				obj.body.poke( adr, (unsigned long)0xc8, 2);
				obj.body.insert( adr+2, rel_jmp(p1,2,3));
			} else {
				norm_err("internal error with opcode '"+obc+"', please report this bug.");
			}
		} else if ( obc == "BSR") {
			if ( num_ext==2 || num_ext == -1 ) {
				obj.body.poke( adr, (unsigned long)0x7, 1);
				obj.body.insert(adr+1, rel_jmp(p1,4,2));
			} else if ( num_ext==3 ) {
				obj.body.poke( adr, (unsigned long)0xe8, 2);
				obj.body.insert( adr+2, rel_jmp(p1,6,3));
			} else {
				norm_err("internal error with opcode '"+obc+"', please report this bug.");
			}
		} else if ( obc == "JMP" ) {
			get_p1lbl(s,x);
			obj.body.poke( adr, (unsigned long)0xd8, 2);
			insert_imm_adr(adr+2, hrval(x,4), true);
		} else if ( obc == "JSR" ) {
			get_p1lbl(s,x);
			obj.body.poke( adr, (unsigned long)0xf8, 2);
			insert_imm_adr(adr+2, hrval(x,4), true);
		} else if ( obc == "BEQ" || obc == "RTEQ" ) {
			if ( smod==4 && dmod==8 ) {
				get_p1val(s,x);
				obj.body.poke( adr, (unsigned long)0x38, 2);
				insert_imm_val( adr+2, hrval(x,0));
				obj.body.insert( adr+3, rel_jmp(p3,3,1));
			} else if ( smod==4 && dmod==6 ) {
				get_p1val(s,x);
				obj.body.poke( adr, (unsigned long)0x98, 2);
				insert_imm_val( adr+2, hrval(x,0));
				obj.body.insert( adr+3, rel_jmp(p3,3,1));
			} else if ( smod==1 && dmod==1 ) {
				int x = sd8_mode(p1,p2);
				if ( num_ext==4 ) {
					obj.body.poke( adr, (unsigned long)0xa8 + (x << 8), 3);
					obj.body.insert( adr+3, rel_jmp(p3,3,1));
				} else if ( alp_ext >= 0 ) {
					obj.body.poke( adr, (unsigned long)0x9 + (alp_ext << 4) + (x << 8), 3);
					obj.body.insert( adr+3, rel_jmp(p3,3,1));
				}
			} else if ( smod==1 && p2=="0" ) {
				if ( num_ext==4 ) {
					obj.body.poke( adr, (unsigned long)0xa8 + ((sd5_mode(p1)+4) << 8), 3);
					obj.body.insert( adr+3, rel_jmp(p3,3,1));
				} else if ( alp_ext >= 0 ) {
					obj.body.poke( adr, (unsigned long)0x9+(alp_ext << 4)+((sd5_mode(p1)+4) << 8), 3);
					obj.body.insert( adr+3, rel_jmp(p3,3,1));
				}
			} else {
				norm_err("internal error with opcode '"+obc+"', please report this bug.");
			}
		} else if ( obc == "BNE" || obc == "RTNE" ) {
			if ( smod==4 && dmod==6 ) {
				get_p1val(s,x);
				obj.body.poke( adr, (unsigned long)0x88, 2);
				insert_imm_val( adr+2, hrval(x,0));
				obj.body.insert( adr+3, rel_jmp(p3,3,1));
			} else if ( smod==1 && dmod==1 ) {
				int x = sd8_mode(p1,p2);
				if ( num_ext == 4) {
					obj.body.poke( adr, (unsigned long)0xa8 + ((x+4) << 8), 3);
					obj.body.insert( adr+3, rel_jmp(p3,3,1));
				} else if ( alp_ext >= 0 ) {
					obj.body.poke( adr, (unsigned long)0x9 + (alp_ext << 4) + ((x+4) << 8), 3);
					obj.body.insert( adr+3, rel_jmp(p3,3,1));
				}
			} else if ( smod==1 && p2=="0" ) {
				if ( num_ext==4 ) {
					obj.body.poke( adr, (unsigned long)0xa8 +  ((sd5_mode(p1)+8) << 8), 3);
					obj.body.insert( adr+3, rel_jmp(p3,3,1));
				} else if ( alp_ext >= 0 ) {
					obj.body.poke( adr, (unsigned long)0x9 + (alp_ext << 4) + ((sd5_mode(p1)+8) << 8),3);
					obj.body.insert( adr+3, rel_jmp(p3,3,1));
				}
			} else {
				norm_err("internal error with opcode '"+obc+"', please report this bug.");
			}
		} else if ( obc == "BLT" || obc == "RTLT") {
			int x = sd9_mode(p1,p2);
			if ( num_ext == 4 ) {
				obj.body.poke( adr, (unsigned long)0xb8 + (x << 8), 3);
				obj.body.insert(adr+3 , rel_jmp(p3,3,1));
			} else if ( alp_ext >= 0) {
				obj.body.poke( adr, (unsigned long)0x9 + ((alp_ext+8) << 4) + (x << 8), 3);
				obj.body.insert(adr+3 , rel_jmp(p3,3,1));
			} else {
				norm_err("internal error with opcode '"+obc+"', please report this bug.");
			}
		} else if ( obc == "BLE" || obc == "RTLE" ) {
			int x = sd9_mode(p1,p2) + 8;
			if ( num_ext == 4 ) {
				obj.body.poke( adr, (unsigned long)0xb8 + (x << 8), 3);
				obj.body.insert(adr+3 , rel_jmp(p3,3,1));
			} else if ( alp_ext >= 0 ) {
				obj.body.poke( adr, (unsigned long)0x9 + ((alp_ext+8) << 4) + (x << 8), 3);
				obj.body.insert(adr+3 , rel_jmp(p3,3,1));
			} else {
				norm_err("internal error with opcode '"+obc+"', please report this bug.");
			}
		} else if ( obc == "BGT" || obc == "RTGT" ) {
			int x = sd10_mode(p1,p2);
			if ( num_ext==4 ) {
				obj.body.poke( adr, (unsigned long)0xb8 + (x << 8), 3);
				obj.body.insert(adr+3 , rel_jmp(p3,3,1));
			} else if ( alp_ext >= 0 ) {
				obj.body.poke( adr, (unsigned long)0x9 + ((alp_ext+8) << 4) + (x << 8), 3);
				obj.body.insert(adr+3 , rel_jmp(p3,3,1));
			} else {
				norm_err("internal error with opcode '"+obc+"', please report this bug.");
			}
		} else if ( obc == "BGE" || obc == "RTGE" ) {
			int x = sd10_mode(p1,p2) + 8;
			if ( num_ext == 4 ) {
				obj.body.poke( adr, (unsigned long)0xb8 + (x << 8), 3);
				obj.body.insert(adr+3 , rel_jmp(p3,3,1));
			} else if ( alp_ext >= 0 ) {
				obj.body.poke( adr, (unsigned long)0x9 + ((alp_ext+8) << 4) + (x << 8), 3);
				obj.body.insert(adr+3 , rel_jmp(p3,3,1));
			} else {
				norm_err("internal error with opcode '"+obc+"', please report this bug.");
			}
		} else if ( obc == "BBC" || obc == "RTBC" ) {
			get_p1val(s,x);
			if ( smod == 4 && dmod == 7 ) {
				obj.body.poke( adr, (unsigned long)0x68, 2);
				insert_imm_val(adr+2, hrval(x,0));
				obj.body.insert(adr+3, rel_jmp(p3,3,1));
			} else if ( smod==4 && p2=="c" ) {
				obj.body.poke( adr, (unsigned long)0xa808, 4);
				insert_imm_val(adr+4, hrval(x,0));
				obj.body.insert(adr+5, rel_jmp(p3,5,1));
			} else if ( smod==4 && p2=="a" ) {
				obj.body.poke( adr, (unsigned long)0x6808, 4);
				insert_imm_val(adr+4, hrval(x,0));
				obj.body.insert(adr+5, rel_jmp(p3,5,1));
			} else {
				norm_err("internal error with opcode '"+obc+"', please report this bug.");
			}
		} else if ( obc == "BBS" || obc == "RTBS" ) {
			get_p1val(s,x);
			if ( smod==4 && dmod==7 ) {
				obj.body.poke( adr, (unsigned long)0x78, 2);
				insert_imm_val( adr+2, hrval(x,0));
				obj.body.insert( adr+3, rel_jmp(p3,3,1));
			} else if ( smod==4 && p2=="c" ) {
				obj.body.poke( adr, (unsigned long)0xb808, 4);
				insert_imm_val(adr+4, hrval(x,0));
				obj.body.insert(adr+5, rel_jmp(p3,5,1));
			} else if ( smod==4 && p2=="a" ) {
				obj.body.poke( adr, (unsigned long)0x7808, 4);
				insert_imm_val(adr+4, hrval(x,0));
				obj.body.insert(adr+5, rel_jmp(p3,5,1));
			} else {
				norm_err("internal error with opcode '"+obc+"', please report this bug.");
			}
		} else if ( obc == "DC" ) { 
			int i = 0;
			while (para.length()) {
				Str e = npara(para);
				s=1;
				unsigned long long x = eval_i(e,s);
				if (s == 1) {
					obj.body.insert( adr + i, hval(x,num_ext));
				}
				i += num_ext + 1;
			}
		} else if ( obc == "DCF" ) { 
			int i = 0;
			while (para.length()) {
				Str e = npara(para);
				s=1;
				double x = eval_d(e,s);
				if (s == 1) {
					obj.body.insert( adr + i, fval(x));
				}
				i += 16;
			}
		} else if ( obc == "DCR" ) {
			int i = 0;
			while (para.length()) {
				last_ext_ref.clear();
				Str e = npara(para);
				s = 1;
				unsigned long long x = eval_i(e,s);
				if ( s == 1 ) {
					insert_imm_val( adr + i, hrval(x,num_ext), (alp_ext == -2));
				}
				i += num_ext + 1;
			}
		} else if ( obc == "DCG" ) {
			int i = 0;
			while (para.length()) {
				Str e = npara(para);
				s = 1;
				unsigned long long x = eval_i(e,s);
				if ( s == 1 ) {
					obj.body.insert( adr + i, hgval(x,num_ext));
				}
				i += num_ext + 1;
			}
		} else if (obc == "XDEF" ) {
			AVLItem<Symbol> * p = l_arr.find(Symbol(p1));
			if (! p) {
				norm_err("cannot XDEF undefined label '"+p1+"'");
			} else {
				if (p->external) {
					norm_err("value of label to XDEF must be known at time of assembly");
				} else {
					obj.exports.insert( *((Symbol *)p) ); // makes a copy!
				}
			}
		} else if (obc == "XREF" ) {
			Symbol * sym = l_arr.find(Symbol(p1));
			if ( !sym ) {
				AVLItem<Symbol> * p = new AVLItem<Symbol> (p1);
				p->isfloat = false;
				p->resolved = true;
				p->external = true;
				p->numerical = false;
				l_arr.insert(p);
			}
		} else {
			norm_err("internal error with opcode '"+obc+"', please report this bug.");
		}	
	} 

	return;

}

int find_mac(const Str & a) {
	int i;
	for ( i=0; i < macros; i++ ) {
		if ( a == m_name[i] ) break;
	}
	if ( i == macros ) {
		return -1;
	} else {
		return i;
	}
}

int read_file(Str f_name) {
	
	int line;
	Str src_label;
	Str src_obc;
	Str src_ext;
	Str src_para;
	Str a;
	Str mac;
	Str mac_src[5];
	Str mac_rpl[5];
	int mac_ll = 0;
	bool macflag = false;
	
	if (verbose) {
		cerr << "reading '" << f_name << "' \n";
	}
	line = 1;
	src.add_tail(SourceLine("", "AKTFILE", "", f_name+(char)1+"1"+(char)1 )); 
	
	ifstream * f;
	f = new ifstream( (char *)f_name);
	if (f->fail()) {
		delete f;
		f_name = incdir_name + f_name;
		f = new ifstream( (char *)f_name);
		if (f->fail()) {
			delete f;
			fatal_err("couldn't open source-file '"+f_name+"'");
			return 20;
		}
	}
	
	while ( ! f->eof() ) {
		if ( macflag ) {
			int x = mac.index(0);
			if ( x != -1) {
				a = mac.before (x);
				mac = mac.after (x);
				for (int i = 0; i < 5; i++) {
					if ( mac_src[i] == "" ) break;
					for (;;) {
						unsigned int z = a.index(mac_src[i]);
						if ( z == (unsigned long)~0 ) break;
						a  = a.before(z) + mac_rpl[i] + a.after(z-1+mac_src[i].length());
					}
				}
				for (;;) {
					unsigned int z = a.index("?cnt?");
					if ( z == (unsigned long)~0 ) break;
					a = a.before(z) + NtoStr(mac_count) + a.after(z+4);
				}
			} else {
				macflag = false;
				a = " AKTFILE "+f_name+","+NtoStr(mac_ll+1);
				line = mac_ll;
			}
		} else {
			char lbuf[200];
			f->getline (lbuf, 200);
			// cout << "LINE=<" << lbuf << ">\n";
			if (f->eof()) break;
			
			if (f->fail()) {
				set_error("error while reading file '"+f_name+"'","");
				return 20;
			}

			/* pre-processor synch support by ATR */
			if (*lbuf == '#') {
				char incfile[strlen(lbuf)];

				sscanf(lbuf, "# %d \"%[^\"]", &line, incfile);
				
				f_name = incfile;
				*lbuf = '\0';
			
				src.add_tail(SourceLine("", "AKTFILE", "", f_name+(char)1+NtoStr(line-1)+(char)1 ));
			}
			a = Str(lbuf);
		}
		
		src_label.clear();
		{
			char i = a.chr(0);
			if ( i != (char)0 && i != (char)9 && i != (char)32 && i != (char)54 ) {
				src_label = nparas(a);
				if ( src_label.chr(0) == 46 ) {
					src_label = last_label + src_label + ".";
				} else {
					if ( src_label.chr(src_label.length()-1) != '.' ) {
						last_label = src_label;
					}
				}
			}
		}
		
		src_obc.clear();
		src_ext.clear();
		
		Str b = nparas(a);
		unsigned long x = b.rindex('.');
		if ( x != (unsigned long)~0 ) {
			src_obc = b.before(x);
			src_obc.to_upper();
			src_ext = b.after(x);
		} else {
			b.to_upper();
			if ( b == "MACRO" ) {
				if (no_mac) {
					set_error("FATAL ERROR: MACRO directive used, but macro support disabled","");
					return 20;
				}
				mac_ll = line;
				m_name[macros] = src_label;
				m_name[macros].to_upper();
				src_label = "";
				for (int i = 0; i < 5; i++) {
					b = nparas(a);
					if (! b.length() ) break;
					m_para[macros*5+i] = b;
				}
				while (! f->eof() ) {
					char lbuf[200];
					f->getline(lbuf,200);
					if (f->eof()) break;
			
					if (f->fail()) {
						set_error("error while reading file '"+f_name+"'","");
						return 20;
					}
					
					a = Str(lbuf);
					
					mac_ll++;
					b = a;
					b.to_upper();
					if ( nparas(b) == "ENDMAC" ) break;
					m_txt[macros] = m_txt[macros]+a+(char)0;
				}
				macros++;
				src_obc = "AKTFILE";
				a = f_name+","+NtoStr(mac_ll+1);
			} else {
				int z;
				if (no_mac) {
					z = -1;
				} else {
					z = find_mac(b);
				}
				if ( z < 0 ) {
					src_obc = b;
				} else {
					mac_count++;
					macflag = true;
					mac_ll = line;
					mac = m_txt[z];

					for ( int i=0 ; i < 5; i++) {
						mac_src[i] = m_para[z*5+i];
						b = nparas(a);
						if ( b == "") break;
						mac_rpl[i] = b;
						if ( b == mac_src[i] ) {
							cerr << "ERROR: macro parameter replacement includes original\n";
							macflag = false;
						}
					}
					a = "";
				}
			}
		}
		
		src_para.clear();
		for (;;) {
			b = nparas(a);
			if ( ! b.length() ) break;
			src_para += b;
			src_para += (char)1;
		}
		
		ListItem<SourceLine> * lis = new ListItem<SourceLine> (
								SourceLine(src_label, src_obc, src_ext, src_para) );
		
		if (lis == 0) return 20;
		src.add_tail(lis);
		line++;

		src_obc.to_upper();
		if ( src_obc == "INCLUDE" ) {
			if (macflag) {
				fatal_err("INCLUDE directives are not allowed inside macros!");
				return 20;
			}
			a = src_para;
			a = npara(a);
			lis->para = "";
			
			streampos f_pos = f->tellg();
			delete f;
			a = a.next_word();
			if (verbose) {
				cerr << "                           \r";
			}
			if (read_file(a)) {
				add_error("unable to read complete file '"+f_name+"'","");
				return 20;
			}
			if (verbose) {
				cerr << "reading '" << f_name << "' \r";
			}
			f = new ifstream ((char *)f_name);
			if (f == 0 || f->fail()) {
				set_error("unable to reopen source file ",(char *)f_name);
				return 20;
			}
			f->seekg(f_pos);
			
			src.add_tail(SourceLine("", "AKTFILE", "", 
							f_name+(char)1+NtoStr(line)+(char)1) );
		}
		
		if ((line & 0xff) == 0) {
			if (verbose) {
				cerr << "reading '" << f_name << "' line " << line << '\r';		
			}
		}
	}
	if (verbose) {
		cerr << "                                                 \r";
	}
	
	delete f;
	
	return 0;
}

int read_source(void) {
	return read_file(src_name);
}

void def_macs(void) {
	if (! no_mac) {
		m_name = new Str[max_macros];
		m_txt = new Str[max_macros];
		m_para = new Str [max_macros*5];
		macros = 0;
	}
}

void pass1(void) {

	// due to a bug in the GNU linker triggered by gcc-2.6.3 optimization,
	// don't make this a static initializer:
	Symbol default_labels[] = {
		Symbol("XM", (unsigned long long) 1),
		Symbol("SB", (unsigned long long) 2),
		Symbol("SR", (unsigned long long) 4),
		Symbol("MP", (unsigned long long) 8)
	};
	
	Symbol * l = default_labels;
	for (int i = 0; i < 4; i++) {
		l->numerical = true;
		l_arr.insert(*l);
		l++;
	}
	
	adr = 0;
	obj.body.clear();

	line = 0;
	akt_line = src.get_head();
	while (akt_line) {
		
// if (akt_line->label.length()) cerr << "label = " << akt_line->label << '\n';
		init_lbl();
		obj.body +=  line_nibs();
		adr += akt_line->binlen;

		if ((line & 0xff) == 0 && verbose) {
			cerr << "pass 1: " << line << " 	\r";
		}
		
		line++;
		akt_line = akt_line->get_next();
	}
	
	nib_len = adr;
	if (verbose) {
		cerr << "                        \r";
	}
}

void pass2(void) {

	adr = 0;
	tmp_lbl = true;

	akt_line = src.get_head();
	line = 0;
	while (akt_line) {
		if (akt_line->label.length()) {
			last_label = akt_line->label;
//cerr << "last_label = " << last_label << '\n';
		}
		line_nibs2();
		adr += akt_line->binlen;
		
		if ((line & 0xff) == 0 && verbose) {
			cerr << "pass 2: " << line << "   \r";
		}
		
		line++;
		akt_line = akt_line->get_next();
	}
		
	if (adr != nib_len) {
		cerr << "ERROR: file length changed between passes (" << nib_len <<
		         " / " << adr << ")\n";
	}
	
	if (verbose) {
		cerr << "                              \r";
	}
}

void passn(void) {
	int msc = 0;
	int sc;
	for (sc = 0; sc < l_arr.size(); sc++) {
		bool solv_rdy = true;
		msc = 1;
		AVLItem<Symbol> * p = l_arr.get_head();
		while (p) {
			if (! p->resolved) {
				if ( p->numerical ) {
					SourceLine * ref_line = p->reference;
					int s = 1;
					Str e(ref_line->para);
					e = npara(e);
					double xf = 0.0;
					unsigned long long xi = 0;
					if (p->isfloat) {
						xf = eval_d(e,s);
					} else {
						xi = eval_i(e,s);
					}
					switch (s) {
					case 0:
						solv_rdy = false;
						msc++;
						break;
					case 1:
						if (p->isfloat) {
							p->fvalue = xf;
						} else {
							p->ivalue = xi;
						}
						p->resolved = true;
						break;
					case -1:
						p->ivalue = 0;
						break;	
					}
				}
			}
			p = l_arr.get_next(p);
		}
		if (verbose) {
			cerr << "pass n[" << sc << "]\r";
		}
		if (solv_rdy || sc>msc) break;
	}
	if (verbose) {
		cerr << "                       \r";
	}
	if (sc > msc) {
		cerr << "unresolvable reference(s) between following labels:\n";
		AVLItem<Symbol> * p = l_arr.get_head(); 
		while (p) {
			if (! p->resolved) {
				cerr << p->name << '\n';
			}
			p = l_arr.get_next(p);
		}		
	}
}


Str cli_arg (int argc, int & aktarg, char ** argv) {
	if (aktarg+1 < argc) {
		aktarg++;
		return Str(argv[aktarg]);
	} else {
		return "";
	}
}

static Str syntax = Str("class invocation syntax:\n"
 "class [-o <objectname>] [-i <include-directory>] \n"
 "      [-exe] [-ul] [-macros] [-mm max_macros] <source-name> \n"
	);

int get_cli_line(int argc, char ** argv) {
	
	int aktarg = 1;
	while (aktarg < argc) {
	
		Str a(argv[aktarg]);
		
		if (a.chr(0) != '-') {
			src_name = a;
		} else if (a == "-a") {
			src_name = cli_arg(argc, aktarg, argv);		
		} else if (a == "-o" ) {
			obj.name = cli_arg(argc, aktarg, argv);
		} else if (a == "-i" ) {
			incdir_name = cli_arg(argc, aktarg, argv);
			if (incdir_name.chr(incdir_name.length()-1) != '/') {
				incdir_name += '/';
			}
		} else if (a == "-mm" ) {
			max_macros = cli_arg(argc, aktarg, argv).val();
		} else if (a == "-ul" ) {
			ul_list = true;
		} else if (a == "-exe") {
			exe_flag = true;
		} else if (a == "-macros") {
			no_mac = false;
		} else if (a == "-v") {
			verbose = true;
		} else {
			cerr << syntax;
			fatal_err("unknown command-line parameter '"+a+"'");
			return 20;
		}
		
		aktarg++;
	}
	
	if ( src_name == "" ) {
		cerr << syntax;
		fatal_err("no source-file specified");
		return 20;
	}
	if ( obj.name == "" ) {
		obj.name = no_ext(src_name)+".o";
	}
	
	return 0;
}

int main (int argc, char ** argv) {
		
	if (get_cli_line(argc, argv)) {
		disp_error();
		return 20;
	}
	
	if (verbose) {
		cerr << "CLASS " << (version_tag+1) << "\nwritten by Lutz Vieweg 1991-1994\n";
	}
	
	def_macs();
	
	if (read_source()) {
		disp_error();
		return 20;
	}
	
	pass1();
	passn();
	pass2();
	
#ifdef OBSOLETE_LIBGXX
	BOstream of;
	of.open(obj.name, ios::out | ios::binary);
#else
	ofstream of( obj.name, ios::out | ios::binary );
#endif
	if (of.fail()) {
		cerr << "FATAL ERROR: unable to open output file '" << obj.name << "'\n";
		return 20;
	}

	int status = 0;
	if (exe_flag) {
		of.write( (char *)obj.body , (obj.body.length()+1) >> 1 );
		status = of.fail();
		if (verbose) {
			cerr << "assembled " << src_name << " to executable ";
		}
	} else {
#ifndef OBSOLETE_LIBGXX
		BOstream bof(of);
		bof << obj;
		status = bof.fail();
#else 
		of << obj;
		status = of.fail();
#endif
		if (verbose) {
			cerr << "assembled " << src_name << " to object-file ";
		}
	}
	
	if (verbose) {
		cerr << obj.name <<  " (" << nib_len << " nibbles)\n";
	}
	if (status) {
		cerr << "FATAL ERROR: write operation on file '" << obj.name << "' failed\n";
		return 20;
	}
	
	if (ul_list) {
			unused_labels();
	}
	
	return !!error_count;
}




syntax highlighted by Code2HTML, v. 0.9.1