
Aktuelle Probleme:
==================

1) Es ist möglich, eine Variable-in-use zu löschen.
	böse(){del gut; return 1}
	var gut; proc gut=böse()
	var gut={1,2,3}; gut[böse()] = ...
	log gut+böse()
usw.

Mit viel Aufwand (TrapVarInUse()) wird versucht, wenigstens das
Löschen von Listen wie globals, locals oder proc bodies, die den
aktuell laufenden Code enthalten, zu schützen. Der Schutz ist
aber löchrig und der Aufwand steigt mit jedem "entdeckten" Loch.


2) Übergabe von großen Listen als proc arguments

Im Gegensatz zum Rückgabewert müssen Prozedurargumente dupliziert
werden, auch wenn sie evtl. nicht verändert werden und 'per reference'
übergeben werden könnten, weil es keine Referenzvariablen gibt.


Lösung:
=======

Die Lösung erfolgt in 3 nacheinander implementierbaren Stufen.
Stufe 2 kann evtl. entfallen oder nach Stufe 3 implementiert werden.


1) Verzicht auf var.parent und var.index

Diese beiden Elemente, über die von einer Variablen auf die
Elternliste zugegriffen werden kann, werden eliminiert.

	Vorteile: zunächst keine.

	Nachteil: Alle Funktionalitäten, die darauf aufbauen, müssen
			  überarbeitet werden, was z.T. ziemlich schwierig wird.
			  - Intersektionstest für Listen
			  - back-to-enclosing-context bei 'private' variablen
			  - in-use-test beim Überschreiben von Listen /
			    Löschen von Variablen
			  - usw.
			  ggf. kann man für die Übergangszeit mit vermehrten
			  Sicherheitsproblemen leben.


2) gesharte Listenvektor

Listen werden dergestalt erweitert, dass der Vektor mit den Zeigern
auf die Listenelemente nicht mehr zu einer Liste gehört.
Statt dessen können die Vektoren von mehreren Listenvariablen geshart
werden, z.B. nach einer Zuweisung listeA = listeB.
Sharing- und Allozzierungs-Mechanismus wie bei den Textvariablen.

	Problem: List-Items gehören nicht mehr eindeutig zu einer Liste.
			 -> Verzicht auf var.parent und var.index unumgänglich.
			 Beim Zuweisen zu Listen oder Überschreiben von List Items
			 muss die Liste,
			 wie bei Strings, auf Beschreibbarkeit geprüft werden.
	Vorteil: Beim Übergeben von Listen als Argument an Prozeduren
			 wird nur noch der Variablenrumpf der Liste dupliziert.
			 Erst beim Überschreiben der Liste wird der Vektor
			 "beschreibbar" gemacht und samt enthaltenen List Items
			 dupliziert.
			 Bei verschachtelten Listen ergibt sich erneut der Vorteil,
			 dass beim Duplizieren der List Items nur jeweils
			 der Variablenrumpf dupliziert wird und der Listenvektor
			 der Sub-Listen zwischen Original und Kopie geshared wird.


3) Usage Counter

Jede Variable erhält als zusätzliches data member einen usage counter
'refcnt'. Variablen können so mehrfach referenziert werden. Werden
sie dupliziert, wird einfach der refcnt erhöht. Werden sie gelöscht,
so wird nur der refcnt erniedrigt und sie werden nur dann gelöscht,
wenn der refcnt 0 wird.

Variablen werden intern nicht mehr per value sondern nur per reference
übergeben. das ist zum überwiegenden teil eh so. Allerdings müssen
alle Variablen nun mit new angelegt werden, es sei denn, es kann
sicher gestellt werden, dass ihr refcnt nicht 0 wird.

	Vorteile: beim Duplizieren des Listenvektors müssen die List Items
			  nun ebenfalls nicht mehr dupliziert werden

			  return <novalue> kann nun ohne Rückgabe eines Null-
			  Pointers implementiert werden:
			  Wie bisher wird an Value() ein pointer auf eine tempzelle
			  übergeben. wird dort hinein ein wert gespeichert,
			  wird der refcnt erhöht. wird kein wert zurückgegeben,
			  so ist der refcnt eben nicht erhöht.

			  Über den refcnt lässt sich wirksamer Löschschutz
			  realisieren: Jedes Mal, wenn ein Zeiger auf eine Variable
			  gestellt wird, wird dort der refcnt erhöht, bis der
			  Zeiger nicht mehr gebraucht wird.
			  - beim duplizieren von list vektoren: aus jeder liste
			    zeigen nun jeweils ein pointer auf jedes list item
			  - zeiger auf zwischenergebnisse in Value()
			  - globals, locals, proc bodies in-use.

			  selbst 'swap' gelingt so schmerzlos ohne intersektions-
			  test, da man effektiv mit swap(a,b){z=a;a=b;b=z} arbeiten
			  kann. beim vertauschen zweier variablen, wovon eine die
			  andere enthält, bleibt so niemals zyklischer ast im
			  speicher zurück.


	Nachteil: zusätzliches data member

			  beim Überschreiben von Variablen muss vorher auf
			  beschreibbarkeit geachtet werden.
			  sowohl bem Überschreiben der Daten als auch des Namens!
			  da ggf. die Variable dazu letztendlich dupliziert werden
			  muss, muss man den pointer auf die Variable ändern können.
			  es genügt also nicht, zu derartigen Funktionen einen
			  Zeiger auf die Variable zu übergeben, sondern man muss
			  den Zeiger selbst per reference übergeben, damit er
			  geändert werden kann.
			  es gilt hier: eine variable <=> ein zeiger.
			  i.A. ist es der zeiger im listenvektor, der ebenfalls
			  bereits beschreibbar sein muss!

			 in Value() muss vor jedem rekursiven aufruf der refcnt
			 des linken operators erhöht und nach rückkehr und
			 durchführen der operation erniedrigt werden. der
			 rückgabewert muss einen inkrementierten refcnt haben.

	Procedere: man sieht den "zeiger auf die Variable" selbst als
			 die eigentliche Variable an.
			 Evtl. eine entsprechende Klasse definieren.
			 Zu prüfen: Overhead, weil der Zeiger so wahrscheinlich
			 nicht mehr in Register gelegt wird.
			 Allerdings werden die Zeiger eh die ganze Zeit per
			 Reference übergeben => prüfen: konnte da der Compiler
			 bisher "per reference" in Registern übergeben?


class VarData
{
	long		cnt;
	vtype		type;
	String		name;

	long		data[sizeof(String)/sizeof(long)];

				VarData		( )			{ cnt = 1; }
				~VarData	( )			{ XXTRAP(cnt>1); /*testet nur, ob static VarData
										  gelöscht wird, auf das noch refs zeigen*/ }
};

class Var
{
	VarData*	data;

				Var			( )			{ data = new VarData(); }
				~Var		( )			{ if (--data->cnt) return; delete data; }
	Var&		Var			( cVar& q )	{ data = q.data; data->cnt++; }
	Var&		operator=	( cVar& q )	{ q.data->cnt++; if (--data->cnt==0) delete data; data=q.data; }

				Var			( VarData& d /*für statische VarData*/ )
										{ data = &d; d.cnt++; /*prevent 'delete' => --var.data.cnt vor löschen der VarData nötig!*/ }

	double		NumValue	( )	const	{ return data->NumValue(); }
	double&		NumValRef	( )			{ if (data->cnt>1) { data->cnt--; data = new VarData(*data); return data->NumRefVal(); }
};























