From: Gert van Valkenhoef Date: Sat, 6 Aug 2011 17:29:18 +0000 (+0100) Subject: Modularize, some progress toward reading stores X-Git-Url: http://deadsoftware.ru/gitweb?a=commitdiff_plain;h=4618e826a4ebe5e60e1d2c419fca7da71657bf9b;p=odcread.git Modularize, some progress toward reading stores --- diff --git a/Makefile b/Makefile index 12f5f8a..e03bf66 100644 --- a/Makefile +++ b/Makefile @@ -1,2 +1,7 @@ -odcread: odcread.cc - g++ -o odcread odcread.cc +HEADERS=oberon.h store.h reader.h domain.h + +odcread: odcread.o reader.o store.o util.o + g++ -o $@ $^ + +%.o: %.cc $(HEADERS) + g++ -c -I. -o $@ $< diff --git a/domain.h b/domain.h new file mode 100644 index 0000000..8fe0f0a --- /dev/null +++ b/domain.h @@ -0,0 +1,12 @@ +#ifndef _DOMAIN_H_ +#define _DOMAIN_H_ + +namespace odc { + +class Domain { + +}; + +} + +#endif // _DOMAIN_H_ diff --git a/oberon.h b/oberon.h new file mode 100644 index 0000000..2f9e39b --- /dev/null +++ b/oberon.h @@ -0,0 +1,70 @@ +#ifndef _OBERON_H_ +#define _OBERON_H_ + +#include + +namespace odc { + /** + * BOOLEAN: 1 byte (0 = FALSE, 1 = TRUE) + */ + typedef bool BOOLEAN; + + /** + * SHORTCHAR 1 byte in the Latin-1 character set (i.e., Unicode page 0; 00X..0FFX) + */ + typedef char SHORTCHAR; + + /** + * CHAR 2 byte in the Unicode character set (0000X..0FFFFX) + * (cannot use wchar_t as its width is not fixed) + */ + typedef uint16_t CHAR; + + /** + * BYTE: 1 byte (-128..127) + */ + typedef int8_t BYTE; + + /** + * SHORTINT: 2 bytes (-32768..32767) + */ + typedef int16_t SHORTINT; + + + /** + * INTEGER: 4 bytes (-2147483648..2147483647) + */ + typedef int32_t INTEGER; + + /** + * LONGINT: 8 bytes (-9223372036854775808..9223372036854775807) + */ + typedef int64_t LONGINT; + + /** + * SHORTREAL: 4 bytes IEEE format + */ + typedef float SHORTREAL; + + /** + * REAL: 8 bytes IEEE format + */ + typedef double REAL; + + /** + * SET: 4 bytes (least significant bit = element 0) + */ + typedef uint32_t SET; + + /** + * Short String: string in the Latin-1 character set, followed by a 00X + * i.e. SHORTCHAR* + * String: string in the Unicode character set, followed by a 0000X + * i.e. CHAR* + */ + + bool isBigEndian(); + bool isLittleEndian(); +} + +#endif diff --git a/odcread.cc b/odcread.cc index b3b00ce..77a2694 100644 --- a/odcread.cc +++ b/odcread.cc @@ -1,435 +1,11 @@ #include #include -#include - -namespace odc { - /** - * INTEGER: 4 bytes (-2147483648..2147483647) - */ - typedef int32_t INTEGER; - - bool isBigEndian() { // http://stackoverflow.com/questions/1001307/detecting-endianness-programmatically-in-a-c-program - union { - uint32_t i; - uint8_t c[4]; - } test = {0x01020304}; - return test.c[0] == 1; - } - bool isLittleEndian() { - return !isBigEndian(); - } - - class Domain { - }; - - class Reader; - - /** - * TYPE Store - * ABSTRACT - * Storable extensible data types like Views.View or TextModels.Text are derived from Store. - * Stores are typically allocated by suitable directories, e.g., Views.Directory or TextModels.Directory. - * Stores are used as base types for all objects that must be both extensible and persistent. - */ - class Store { - public: - /** - * PROCEDURE (s: Store) Domain (): Domain - * NEW - * A store may be associated with a domain. This is done by the procedure InitDomain, which assigns a domain to the store. - * Domain may be called by arbitrary clients. - */ - Domain* getDomain() { - return 0; - } - - /** - * PROCEDURE (s: Store) CopyFrom- (source: Store) - * NEW, EMPTY - * Copy the contents of source to s. Copying is a deep copy. - * - * Pre - * source # NIL guaranteed - * TYP(source) = TYP(s) guaranteed - * s.Domain() = NIL guaranteed - * s is not yet initialized guaranteed - */ - // FIXME - /** - * PROCEDURE (s: Store) Internalize- (VAR rd: Reader) - * NEW, EMPTY - * (For backward compatibility, this method is actually still EXTENSIBLE. This may change in the future.) - * Reads the contents of s from reader rd. Internalize must read the same (amount of) data as is written by the corresponding Externalize procedure. - * Internalize is called locally. - * Internalize is extended by various persistent object types, e.g., models, views, and controllers. - * - * Pre - * source.Domain() = NIL guaranteed - * source is not yet initialized guaranteed - */ - void internalize(Reader &reader) { -// PROCEDURE (s: Store) Internalize- (VAR rd: Reader), NEW, EXTENSIBLE; -// VAR thisVersion: INTEGER; -// BEGIN -// rd.ReadVersion(minVersion, maxStoreVersion, thisVersion); -// IF ~rd.cancelled & s.isElem THEN -// rd.ReadVersion(minVersion, maxStoreVersion, thisVersion) -// (* works since maxStoreVersion = maxElemVersion = 0 in pre-1.3 *) -// END -// END Internalize; - } - - /** - * PROCEDURE (s: Store) Externalize- (VAR wr: Writer) - * NEW, EMPTY - * (For backward compatibility, this method is actually still EXTENSIBLE. This may change in the future.) - * Write the contents of s to writer wr. Externalize must write the same (amount of) data as is read by the corresponding Internalize procedure. - * Externalize ist called locally. - * Externalize is extended by various persistent object types, e.g., models, views, and controllers. - */ - // FIXME - - /** - * PROCEDURE (s: Store) ExternalizeAs- (VAR s1: Store) - * NEW, EMPTY - * Before a store's Externalize procedure is called, its ExternalizeAs procedure is called, which gives the store the opportunity to denote another store that should be externalized in its place (a "proxy"). It is also possible to set s1 to NIL, which means that the store should not be externalized at all. This is used e.g. for compiler error markers, which are never stored. - * ExternalizeAs ist called locally. - * - * Pre - * s1 = s guaranteed - */ - // FIXME - }; - - /** - * TYPE Reader - * Reader for Component Pascal values like integers, reals, or sets. A reader contains a Files.Reader, to which it forwards most operations. - * Readers are used in the Store.Internalize procedure. - * Readers are not extensible. - */ - class Reader { - private: - /* - * rider-: Files.Reader - * The file rider which links a Reader to a file. - */ - std::istream &d_rider; - - /* - * cancelled-: BOOLEAN valid during a Store.Internalize call - * Tells whether the currently executing Internalize has been called by ReadVersion or TurnIntoAlien. - */ - bool d_cancelled; - - /** - * readAlien-: BOOLEAN - * Tells whether any alien has been read since the last ConnectTo. - */ - bool d_readAlien; - - public: - Reader(std::istream &rider): d_rider(rider), d_cancelled(false), d_readAlien(false) {} - - /** - * PROCEDURE (VAR rd: Reader) ConnectTo (f: Files.File) - * NEW - * Connect the reader to a file. All the following operations require connected readers, i.e., rd.rider # NIL. This precondition is not checked explicitly, however. After connecting, the reader's position is at the beginning of the file. If the same reader should be reused on another file, it must first be closed, by connecting it to NIL. - * ConnectTo is used internally. - * - * Pre - * 20 (f = NIL) OR (rd.rider = NIL) - * - * Post - * f = NIL - * rd.rider = NIL - * f # NIL - * (rd.rider # NIL) & (rd.rider.Base() = f) - * rd.Pos() = 0 - */ - // FIXME - - /** - * PROCEDURE (VAR rd: Reader) Pos (): INTEGER - * NEW - * Returns the reader's current position. - * - * Post - * 0 <= result <= rd.rider.Base().Length() - */ - // FIXME - - /** - * PROCEDURE (VAR rd: Reader) SetPos (pos: INTEGER) - * NEW - * Sets the reader's current position to pos. - * - * Pre - * 20 pos >= 0 - * 21 pos <= rd.rider.Base().Length() - * - * Post - * rd.Pos() = pos - * ~rd.rider.eof - */ - // FIXME - - /** - * PROCEDURE (VAR rd: Reader) ReadBool (OUT x: BOOLEAN) - * NEW - * Reads a Boolean value. - * - * PROCEDURE (VAR rd: Reader) ReadSChar (OUT x: SHORTCHAR) - * NEW - * Reads a short character (00X..0FFX). - * - * PROCEDURE (VAR rd: Reader) ReadXChar (OUT x: CHAR) - * NEW - * Same as ReadSChar, but has a CHAR-type parameter. - * This procedure is provided to simplify migration from Release 1.2 to 1.3. - * - * PROCEDURE (VAR rd: Reader) ReadChar (OUT x: CHAR) - * NEW - * Reads a character (0000X..0FFFFX). - * - * PROCEDURE (VAR rd: Reader) ReadByte (OUT x: BYTE) - * NEW - * Reads a very short integer (-128..127). - * - * PROCEDURE (VAR rd: Reader) ReadSInt (OUT x: SHORTINT) - * NEW - * Reads a short integer (-32768..32767). - * - * PROCEDURE (VAR rd: Reader) ReadXInt (OUT x: INTEGER) - * NEW - * Same as ReadSInt, but has an INTEGER-type parameter. - * This procedure is provided to simplify migration from Release 1.2 to 1.3. - */ - - /** - * PROCEDURE (VAR rd: Reader) ReadInt (OUT x: INTEGER) - * NEW - * Reads an integer (-2147483648..2147483647). - */ - INTEGER readInt() { - char *buf = new char[4]; - d_rider.read(buf, 4); - if (isLittleEndian()) { - return *(INTEGER *)buf; - } else { - char *out = new char[4]; - out[0] = buf[3]; out[1] = buf[2]; out[2] = buf[1]; out[3] = buf[0]; - return *(INTEGER *)out; - } - } - - /* - * PROCEDURE (VAR rd: Reader) ReadLong (OUT x: LONGINT) - * NEW - * Reads a long integer (-9223372036854775808..9223372036854775807). - * - * PROCEDURE (VAR rd: Reader) ReadSReal (OUT x: SHORTREAL) - * NEW - * Reads a short real (32-bit IEEE number). - * - * PROCEDURE (VAR rd: Reader) ReadXReal (OUT x: REAL) - * NEW - * Same as ReadSReal, but has a REAL-type parameter. - * This procedure is provided to simplify migration from Release 1.2 to 1.3. - * - * PROCEDURE (VAR rd: Reader) ReadReal (OUT x: REAL) - * NEW - * Reads a real (64-bit IEEE number). - * - * PROCEDURE (VAR rd: Reader) ReadSet (OUT x: SET) - * NEW - * Reads a set (32 elements). - * - * PROCEDURE (VAR rd: Reader) ReadSString (OUT x: ARRAY OF SHORTCHAR) - * NEW - * Reads a 0X-terminated short string. - * - * Pre - * invalid index LEN(x) > Length(string) - * - * PROCEDURE (VAR rd: Reader) ReadXString (OUT x: ARRAY OF CHAR) - * NEW - * Same as ReadSString, but has a string-type parameter. - * This procedure is provided to simplify migration from Release 1.2 to 1.3. - * - * PROCEDURE (VAR rd: Reader) ReadString (OUT x: ARRAY OF CHAR) - * NEW - * Reads a 0X-terminated string. - * - * Pre - * invalid index LEN(x) > Length(string) - * - * PROCEDURE (VAR rd: Reader) ReadStore (OUT x: Store) - * NEW - * Reads a store's type, allocates it, and then reads its contents, by calling the store's Internalize procedure. x may also be NIL, or an alien if the store's module cannot be loaded, or if internalization has been cancelled by the Internalize procedure. - * If the store has already been read in, a pointer to the same store is returned instead of allocating a new one. This means that arbitrary graphs that have been written with WriteStore are reconstructed correctly, including alias pointers to the same store, cycles, etc. - * If the file on which the reader operates does not contain correct input, then an assertion trap will be caused (traps 101 to trap 106). - * - * Pre - * 20 the reader is at the start position of a new store - * - * Post - * empty store on file - * x = NIL - * non-empty store on file - * x # NIL - * x IS Alien - * x.cause # 0 - * x.type # "" - * x.file # NIL - * x.pos >= 0 beginning of store's data - * x.len >= 0 length of store's data - * alien store contents are on x.file in the range [x.pos .. x.pos + x.len[. - * These data include only the store's contents, not its prefix - * ~(x IS Alien) - * x was read successfully - */ - Store *readStore() { - return new Store(); - } -// PROCEDURE (VAR rd: Reader) ReadStore* (OUT x: Store), NEW; -// VAR a: Alien; t: Kernel.Type; -// len, pos, pos1, id, comment, next, down, downPos, nextTypeId, nextElemId, nextStoreId: INTEGER; -// kind: SHORTCHAR; path: TypePath; type: TypeName; -// save: ReaderState; -// BEGIN -// rd.ReadSChar(kind); -// IF kind = nil THEN -// rd.ReadInt(comment); rd.ReadInt(next); -// rd.st.end := rd.Pos(); -// IF (next > 0) OR ((next = 0) & ODD(comment)) THEN rd.st.next := rd.st.end + next ELSE rd.st.next := 0 END; -// x := NIL -// ELSIF kind = link THEN -// rd.ReadInt(id); rd.ReadInt(comment); rd.ReadInt(next); -// rd.st.end := rd.Pos(); -// IF (next > 0) OR ((next = 0) & ODD(comment)) THEN rd.st.next := rd.st.end + next ELSE rd.st.next := 0 END; -// x := ThisStore(rd.eDict, id) -// ELSIF kind = newlink THEN -// rd.ReadInt(id); rd.ReadInt(comment); rd.ReadInt(next); -// rd.st.end := rd.Pos(); -// IF (next > 0) OR ((next = 0) & ODD(comment)) THEN rd.st.next := rd.st.end + next ELSE rd.st.next := 0 END; -// x := ThisStore(rd.sDict, id) -// ELSIF (kind = store) OR (kind = elem) THEN -// IF kind = elem THEN -// id := rd.nextElemId; INC(rd.nextElemId) -// ELSE -// id := rd.nextStoreId; INC(rd.nextStoreId) -// END; -// ReadPath(rd, path); type := path[0]; -// nextTypeId := rd.nextTypeId; nextElemId := rd.nextElemId; nextStoreId := rd.nextStoreId; -// rd.ReadInt(comment); -// pos1 := rd.Pos(); -// rd.ReadInt(next); rd.ReadInt(down); rd.ReadInt(len); -// pos := rd.Pos(); -// IF next > 0 THEN rd.st.next := pos1 + next + 4 ELSE rd.st.next := 0 END; -// IF down > 0 THEN downPos := pos1 + down + 8 ELSE downPos := 0 END; -// rd.st.end := pos + len; -// rd.cause := 0; -// ASSERT(len >= 0, 101); -// IF next # 0 THEN -// ASSERT(rd.st.next > pos1, 102); -// IF down # 0 THEN -// ASSERT(downPos < rd.st.next, 103) -// END -// END; -// IF down # 0 THEN -// ASSERT(downPos > pos1, 104); -// ASSERT(downPos < rd.st.end, 105) -// END; -// t := ThisType(type); -// IF t # NIL THEN -// x := NewStore(t); x.isElem := kind = elem -// ELSE -// rd.cause := thisTypeRes; AlienTypeReport(rd.cause, type); -// x := NIL -// END; -// IF x # NIL THEN -// IF SamePath(t, path) THEN -// IF kind = elem THEN -// x.id := id; AddStore(rd.eDict, rd.eHead, x) -// ELSE -// x.id := id; AddStore(rd.sDict, rd.sHead, x) -// END; -// save := rd.st; rd.cause := 0; rd.cancelled := FALSE; -// x.Internalize(rd); -// rd.st := save; -// IF rd.cause # 0 THEN x := NIL -// ELSIF (rd.Pos() # rd.st.end) OR rd.rider.eof THEN -// rd.cause := inconsistentVersion; AlienReport(rd.cause); -// x := NIL -// END -// ELSE -// rd.cause := inconsistentType; AlienTypeReport(rd.cause, type); -// x := NIL -// END -// END; -// -// IF x # NIL THEN -// IF rd.noDomain THEN -// rd.store := x; -// rd.noDomain := FALSE -// ELSE -// Join(rd.store, x) -// END -// ELSE (* x is an alien *) -// rd.SetPos(pos); -// ASSERT(rd.cause # 0, 107); -// NEW(a); a.path := path; a.cause := rd.cause; a.file := rd.rider.Base(); -// IF rd.noDomain THEN -// rd.store := a; -// rd.noDomain := FALSE -// ELSE -// Join(rd.store, a) -// END; -// IF kind = elem THEN -// a.id := id; AddStore(rd.eDict, rd.eHead, a) -// ELSE -// a.id := id; AddStore(rd.sDict, rd.sHead, a) -// END; -// save := rd.st; -// rd.nextTypeId := nextTypeId; rd.nextElemId := nextElemId; rd.nextStoreId := nextStoreId; -// InternalizeAlien(rd, a.comps, downPos, pos, len); -// rd.st := save; -// x := a; -// ASSERT(rd.Pos() = rd.st.end, 108); -// rd.cause := 0; rd.cancelled := FALSE; rd.readAlien := TRUE -// END -// ELSE -// pos := rd.Pos(); -// HALT(20) -// END -// END ReadStore; - /** - * PROCEDURE (VAR rd: Reader) ReadVersion (min, max: INTEGER; OUT version: INTEGER) - * NEW - * Read a version byte and return it in version. If version is not in the specified range [min .. max], the store currently being read is turned into an alien, with cause = alienVersion. - * - * Pre - * 20 0 <= min <= max - * - * Post - * min <= version <= max - * legal version - * (version < min) OR (version > max) - * illegal version - * rd.cause = alienVersion - * rd.cancelled - * rd.readAlien - * - * PROCEDURE (VAR rd: Reader) TurnIntoAlien (cause: INTEGER) - * NEW - * A store which is currently being internalized can turn itself into an alien, e.g., if it has read a component store which is an alien. - * - * Pre - * 20 cause > 0 - */ - }; +#include +#include +#include +namespace odc { Store* importDocument(std::istream &is) { const INTEGER docTag = 0x6F4F4443; const INTEGER docVersion = 0; diff --git a/reader.cc b/reader.cc new file mode 100644 index 0000000..54ca8c1 --- /dev/null +++ b/reader.cc @@ -0,0 +1,216 @@ +#include + +namespace odc { + +Reader::Reader(std::istream &rider): d_rider(rider), d_cancelled(false), d_readAlien(false) {} + +SHORTCHAR Reader::readSChar() { + SHORTCHAR out; + d_rider.read(&out, 1); + return out; +} + +INTEGER Reader::readInt() { + char *buf = new char[4]; + d_rider.read(buf, 4); + if (isLittleEndian()) { + return *(INTEGER *)buf; + } else { + char *out = new char[4]; + out[0] = buf[3]; out[1] = buf[2]; out[2] = buf[1]; out[3] = buf[0]; + return *(INTEGER *)out; + } +} + +Store* Reader::readStore() { + SHORTCHAR kind = readSChar(); + if (kind == Store::NIL) { + return readNilStore(); + } else if (kind == Store::LINK) { + return readLinkStore(); + } else if (kind == Store::NEWLINK) { + return readNewLinkStore(); + } else if (kind == Store::STORE) { + return readStoreOrElemStore(false); + } else if (kind == Store::ELEM) { + return readStoreOrElemStore(true); + } else { + throw 20; + } +} +// PROCEDURE (VAR rd: Reader) ReadStore* (OUT x: Store), NEW; +// VAR a: Alien; t: Kernel.Type; +// len, pos, pos1, id, comment, next, down, downPos, nextTypeId, nextElemId, nextStoreId: INTEGER; +// kind: SHORTCHAR; path: TypePath; type: TypeName; +// save: ReaderState; +Store *Reader::readNilStore() { + return 0; +} +// IF kind = nil THEN +// rd.ReadInt(comment); rd.ReadInt(next); +// rd.st.end := rd.Pos(); +// IF (next > 0) OR ((next = 0) & ODD(comment)) THEN rd.st.next := rd.st.end + next ELSE rd.st.next := 0 END; +// x := NIL +Store *Reader::readLinkStore() { + return 0; +} +// ELSIF kind = link THEN +// rd.ReadInt(id); rd.ReadInt(comment); rd.ReadInt(next); +// rd.st.end := rd.Pos(); +// IF (next > 0) OR ((next = 0) & ODD(comment)) THEN rd.st.next := rd.st.end + next ELSE rd.st.next := 0 END; +// x := ThisStore(rd.eDict, id) +Store *Reader::readNewLinkStore() { + return 0; +} +// ELSIF kind = newlink THEN +// rd.ReadInt(id); rd.ReadInt(comment); rd.ReadInt(next); +// rd.st.end := rd.Pos(); +// IF (next > 0) OR ((next = 0) & ODD(comment)) THEN rd.st.next := rd.st.end + next ELSE rd.st.next := 0 END; +// x := ThisStore(rd.sDict, id) + +Store *Reader::readStoreOrElemStore(bool isElem) { + INTEGER id = isElem ? d_nextElemId++ : d_nextStoreId++; + CHAR** path = newTypePath(); + readPath(path); + CHAR* type = path[0]; + std::cout << type << std::endl; + INTEGER comment = readInt(); + return 0; +} +// ReadPath(rd, path); type := path[0]; +// nextTypeId := rd.nextTypeId; nextElemId := rd.nextElemId; nextStoreId := rd.nextStoreId; +// rd.ReadInt(comment); +// pos1 := rd.Pos(); +// rd.ReadInt(next); rd.ReadInt(down); rd.ReadInt(len); +// pos := rd.Pos(); +// IF next > 0 THEN rd.st.next := pos1 + next + 4 ELSE rd.st.next := 0 END; +// IF down > 0 THEN downPos := pos1 + down + 8 ELSE downPos := 0 END; +// rd.st.end := pos + len; +// rd.cause := 0; +// ASSERT(len >= 0, 101); +// IF next # 0 THEN +// ASSERT(rd.st.next > pos1, 102); +// IF down # 0 THEN +// ASSERT(downPos < rd.st.next, 103) +// END +// END; +// IF down # 0 THEN +// ASSERT(downPos > pos1, 104); +// ASSERT(downPos < rd.st.end, 105) +// END; +// t := ThisType(type); +// IF t # NIL THEN +// x := NewStore(t); x.isElem := kind = elem +// ELSE +// rd.cause := thisTypeRes; AlienTypeReport(rd.cause, type); +// x := NIL +// END; +// IF x # NIL THEN +// IF SamePath(t, path) THEN +// IF kind = elem THEN +// x.id := id; AddStore(rd.eDict, rd.eHead, x) +// ELSE +// x.id := id; AddStore(rd.sDict, rd.sHead, x) +// END; +// save := rd.st; rd.cause := 0; rd.cancelled := FALSE; +// x.Internalize(rd); +// rd.st := save; +// IF rd.cause # 0 THEN x := NIL +// ELSIF (rd.Pos() # rd.st.end) OR rd.rider.eof THEN +// rd.cause := inconsistentVersion; AlienReport(rd.cause); +// x := NIL +// END +// ELSE +// rd.cause := inconsistentType; AlienTypeReport(rd.cause, type); +// x := NIL +// END +// END; +// +// IF x # NIL THEN +// IF rd.noDomain THEN +// rd.store := x; +// rd.noDomain := FALSE +// ELSE +// Join(rd.store, x) +// END +// ELSE (* x is an alien *) +// rd.SetPos(pos); +// ASSERT(rd.cause # 0, 107); +// NEW(a); a.path := path; a.cause := rd.cause; a.file := rd.rider.Base(); +// IF rd.noDomain THEN +// rd.store := a; +// rd.noDomain := FALSE +// ELSE +// Join(rd.store, a) +// END; +// IF kind = elem THEN +// a.id := id; AddStore(rd.eDict, rd.eHead, a) +// ELSE +// a.id := id; AddStore(rd.sDict, rd.sHead, a) +// END; +// save := rd.st; +// rd.nextTypeId := nextTypeId; rd.nextElemId := nextElemId; rd.nextStoreId := nextStoreId; +// InternalizeAlien(rd, a.comps, downPos, pos, len); +// rd.st := save; +// x := a; +// ASSERT(rd.Pos() = rd.st.end, 108); +// rd.cause := 0; rd.cancelled := FALSE; rd.readAlien := TRUE +// END + +void Reader::readPath(CHAR **path) { + SHORTCHAR kind = readSChar(); + for (int i = 0; kind == Store::NEWEXT; ++i) { + std::cout << "NEWEXT" << std::endl; + //readXString(path[i]); +// AddPathComp(rd); INC(rd.nextTypeId); +// IF path[i] # elemTName THEN INC(i) END; +// rd.ReadSChar(kind) + } + + if (kind == Store::NEWBASE) { + std::cout << "NEWBASE" << std::endl; + } else if (kind == Store::OLDTYPE) { + std::cout << "OLDTYPE" << std::endl; + } else { + throw 100; + } + + // FIXME + path[0][0] = 'H'; + path[0][1] = 'i'; + path[0][2] = 0; +} +// PROCEDURE ReadPath (VAR rd: Reader; VAR path: TypePath); +// VAR h: TypeDict; id, extId: INTEGER; i: INTEGER; kind: SHORTCHAR; +// +// PROCEDURE AddPathComp (VAR rd: Reader); +// BEGIN +// IF h # NIL THEN AddBaseId(h, extId, rd.nextTypeId) END; +// AddType(rd.tDict, rd.tHead, rd.nextTypeId, path[i]); +// h := rd.tHead; extId := rd.nextTypeId +// END AddPathComp; +// +// BEGIN +// h := NIL; i := 0; rd.ReadSChar(kind); +// WHILE kind = newExt DO +// rd.ReadXString(path[i]); +// AddPathComp(rd); INC(rd.nextTypeId); +// IF path[i] # elemTName THEN INC(i) END; +// rd.ReadSChar(kind) +// END; +// IF kind = newBase THEN +// rd.ReadXString(path[i]); +// AddPathComp(rd); INC(rd.nextTypeId); INC(i) +// ELSE +// ASSERT(kind = oldType, 100); +// rd.ReadInt(id); +// IF h # NIL THEN AddBaseId(h, extId, id) END; +// REPEAT +// GetThisType(rd.tDict, id, path[i]); id := ThisBaseId(rd.tDict, id); +// IF path[i] # elemTName THEN INC(i) END +// UNTIL id = -1 +// END; +// path[i] := "" +// END ReadPath; + +} // namespace odc diff --git a/reader.h b/reader.h new file mode 100644 index 0000000..cfd4fc5 --- /dev/null +++ b/reader.h @@ -0,0 +1,248 @@ +#ifndef _READER_H_ +#define _READER_H_ + +#include + +#include +#include + +namespace odc { + +/** + * TYPE Reader + * Reader for Component Pascal values like integers, reals, or sets. A reader contains a Files.Reader, to which it forwards most operations. + * Readers are used in the Store.Internalize procedure. + * Readers are not extensible. + */ +class Reader { +private: + /* + * rider-: Files.Reader + * The file rider which links a Reader to a file. + */ + std::istream &d_rider; + + /* + * cancelled-: BOOLEAN valid during a Store.Internalize call + * Tells whether the currently executing Internalize has been called by ReadVersion or TurnIntoAlien. + */ + bool d_cancelled; + + /** + * readAlien-: BOOLEAN + * Tells whether any alien has been read since the last ConnectTo. + */ + bool d_readAlien; + + INTEGER d_nextElemId; + INTEGER d_nextStoreId; + + public: + /** + * Construct a reader from the istream rider. + * @param rider An istream (binary mode). + */ + Reader(std::istream &rider); + + /** + * PROCEDURE (VAR rd: Reader) ConnectTo (f: Files.File) + * NEW + * Connect the reader to a file. All the following operations require connected readers, i.e., rd.rider # NIL. This precondition is not checked explicitly, however. After connecting, the reader's position is at the beginning of the file. If the same reader should be reused on another file, it must first be closed, by connecting it to NIL. + * ConnectTo is used internally. + * + * Pre + * 20 (f = NIL) OR (rd.rider = NIL) + * + * Post + * f = NIL + * rd.rider = NIL + * f # NIL + * (rd.rider # NIL) & (rd.rider.Base() = f) + * rd.Pos() = 0 + */ + // FIXME + + /** + * PROCEDURE (VAR rd: Reader) Pos (): INTEGER + * NEW + * Returns the reader's current position. + * + * Post + * 0 <= result <= rd.rider.Base().Length() + */ + // FIXME + + /** + * PROCEDURE (VAR rd: Reader) SetPos (pos: INTEGER) + * NEW + * Sets the reader's current position to pos. + * + * Pre + * 20 pos >= 0 + * 21 pos <= rd.rider.Base().Length() + * + * Post + * rd.Pos() = pos + * ~rd.rider.eof + */ + // FIXME + + /** + * PROCEDURE (VAR rd: Reader) ReadBool (OUT x: BOOLEAN) + * NEW + * Reads a Boolean value. + */ + /** + * PROCEDURE (VAR rd: Reader) ReadSChar (OUT x: SHORTCHAR) + * NEW + * Reads a short character (00X..0FFX). + */ + SHORTCHAR readSChar(); + /* PROCEDURE (VAR rd: Reader) ReadXChar (OUT x: CHAR) + * NEW + * Same as ReadSChar, but has a CHAR-type parameter. + * This procedure is provided to simplify migration from Release 1.2 to 1.3. + * + * PROCEDURE (VAR rd: Reader) ReadChar (OUT x: CHAR) + * NEW + * Reads a character (0000X..0FFFFX). + * + * PROCEDURE (VAR rd: Reader) ReadByte (OUT x: BYTE) + * NEW + * Reads a very short integer (-128..127). + * + * PROCEDURE (VAR rd: Reader) ReadSInt (OUT x: SHORTINT) + * NEW + * Reads a short integer (-32768..32767). + * + * PROCEDURE (VAR rd: Reader) ReadXInt (OUT x: INTEGER) + * NEW + * Same as ReadSInt, but has an INTEGER-type parameter. + * This procedure is provided to simplify migration from Release 1.2 to 1.3. + */ + + /** + * PROCEDURE (VAR rd: Reader) ReadInt (OUT x: INTEGER) + * NEW + * Reads an integer (-2147483648..2147483647). + */ + INTEGER readInt(); + /* + * PROCEDURE (VAR rd: Reader) ReadLong (OUT x: LONGINT) + * NEW + * Reads a long integer (-9223372036854775808..9223372036854775807). + * + * PROCEDURE (VAR rd: Reader) ReadSReal (OUT x: SHORTREAL) + * NEW + * Reads a short real (32-bit IEEE number). + * + * PROCEDURE (VAR rd: Reader) ReadXReal (OUT x: REAL) + * NEW + * Same as ReadSReal, but has a REAL-type parameter. + * This procedure is provided to simplify migration from Release 1.2 to 1.3. + * + * PROCEDURE (VAR rd: Reader) ReadReal (OUT x: REAL) + * NEW + * Reads a real (64-bit IEEE number). + * + * PROCEDURE (VAR rd: Reader) ReadSet (OUT x: SET) + * NEW + * Reads a set (32 elements). + * + * PROCEDURE (VAR rd: Reader) ReadSString (OUT x: ARRAY OF SHORTCHAR) + * NEW + * Reads a 0X-terminated short string. + * + * Pre + * invalid index LEN(x) > Length(string) + * + * PROCEDURE (VAR rd: Reader) ReadXString (OUT x: ARRAY OF CHAR) + * NEW + * Same as ReadSString, but has a string-type parameter. + * This procedure is provided to simplify migration from Release 1.2 to 1.3. + * + * PROCEDURE (VAR rd: Reader) ReadString (OUT x: ARRAY OF CHAR) + * NEW + * Reads a 0X-terminated string. + * + * Pre + * invalid index LEN(x) > Length(string) + * + * PROCEDURE (VAR rd: Reader) ReadStore (OUT x: Store) + * NEW + * Reads a store's type, allocates it, and then reads its contents, by calling the store's Internalize procedure. x may also be NIL, or an alien if the store's module cannot be loaded, or if internalization has been cancelled by the Internalize procedure. + * If the store has already been read in, a pointer to the same store is returned instead of allocating a new one. This means that arbitrary graphs that have been written with WriteStore are reconstructed correctly, including alias pointers to the same store, cycles, etc. + * If the file on which the reader operates does not contain correct input, then an assertion trap will be caused (traps 101 to trap 106). + * + * Pre + * 20 the reader is at the start position of a new store + * + * Post + * empty store on file + * x = NIL + * non-empty store on file + * x # NIL + * x IS Alien + * x.cause # 0 + * x.type # "" + * x.file # NIL + * x.pos >= 0 beginning of store's data + * x.len >= 0 length of store's data + * alien store contents are on x.file in the range [x.pos .. x.pos + x.len[. + * These data include only the store's contents, not its prefix + * ~(x IS Alien) + * x was read successfully + */ + Store *readStore(); + /** + * PROCEDURE (VAR rd: Reader) ReadVersion (min, max: INTEGER; OUT version: INTEGER) + * NEW + * Read a version byte and return it in version. If version is not in the specified range [min .. max], the store currently being read is turned into an alien, with cause = alienVersion. + * + * Pre + * 20 0 <= min <= max + * + * Post + * min <= version <= max + * legal version + * (version < min) OR (version > max) + * illegal version + * rd.cause = alienVersion + * rd.cancelled + * rd.readAlien + * + * PROCEDURE (VAR rd: Reader) TurnIntoAlien (cause: INTEGER) + * NEW + * A store which is currently being internalized can turn itself into an alien, e.g., if it has read a component store which is an alien. + * + * Pre + * 20 cause > 0 + */ + + private: + Store *readStoreOrElemStore(bool isElem); + Store *readNilStore(); + Store *readLinkStore(); + Store *readNewLinkStore(); + + /* + TypeName* = ARRAY 64 OF CHAR; + TypePath* = ARRAY 16 OF TypeName; + OpName* = ARRAY 32 OF CHAR; + */ + inline CHAR *newTypeName() { + return new CHAR[64]; + } + inline CHAR **newTypePath() { + CHAR **out = new CHAR*[16]; + for (int i = 0; i < 16; ++i) { + out[i] = newTypeName(); + } + return out; + } + void readPath(CHAR **path); +}; + +} // namespace odc + +#endif // _READER_H_ diff --git a/store.cc b/store.cc new file mode 100644 index 0000000..51729e1 --- /dev/null +++ b/store.cc @@ -0,0 +1,9 @@ +#include + +namespace odc { + +Domain* Store::getDomain() { + return 0; +} + +} diff --git a/store.h b/store.h new file mode 100644 index 0000000..381cca7 --- /dev/null +++ b/store.h @@ -0,0 +1,94 @@ +#ifndef _STORE_H_ +#define _STORE_H_ + +#include +#include + +namespace odc { + + /** + * TYPE Store + * ABSTRACT + * Storable extensible data types like Views.View or TextModels.Text are derived from Store. + * Stores are typically allocated by suitable directories, e.g., Views.Directory or TextModels.Directory. + * Stores are used as base types for all objects that must be both extensible and persistent. + */ + class Store { + public: + static const SHORTCHAR NEWBASE = 0xF0; // (* new base type (level = 0), i.e. not yet in dict *) + static const SHORTCHAR NEWEXT = 0xF1; // (* new extension type (level = 1), i.e. not yet in dict *) + static const SHORTCHAR OLDTYPE = 0xF2; // (* old type, i.e. already in dict *) + static const SHORTCHAR NIL = 0x80; // (* nil store *) + static const SHORTCHAR LINK = 0x81; // (* link to another elem in same file *) + static const SHORTCHAR STORE = 0x82; // (* general store *) + static const SHORTCHAR ELEM = 0x83; // (* elem store *) + static const SHORTCHAR NEWLINK = 0x84; // (* link to another non-elem store in same file *) + /** + * PROCEDURE (s: Store) Domain (): Domain + * NEW + * A store may be associated with a domain. This is done by the procedure InitDomain, which assigns a domain to the store. + * Domain may be called by arbitrary clients. + */ + Domain* getDomain(); + + /** + * PROCEDURE (s: Store) CopyFrom- (source: Store) + * NEW, EMPTY + * Copy the contents of source to s. Copying is a deep copy. + * + * Pre + * source # NIL guaranteed + * TYP(source) = TYP(s) guaranteed + * s.Domain() = NIL guaranteed + * s is not yet initialized guaranteed + */ + // FIXME + /** + * PROCEDURE (s: Store) Internalize- (VAR rd: Reader) + * NEW, EMPTY + * (For backward compatibility, this method is actually still EXTENSIBLE. This may change in the future.) + * Reads the contents of s from reader rd. Internalize must read the same (amount of) data as is written by the corresponding Externalize procedure. + * Internalize is called locally. + * Internalize is extended by various persistent object types, e.g., models, views, and controllers. + * + * Pre + * source.Domain() = NIL guaranteed + * source is not yet initialized guaranteed + */ +// void internalize(Reader &reader) { +// PROCEDURE (s: Store) Internalize- (VAR rd: Reader), NEW, EXTENSIBLE; +// VAR thisVersion: INTEGER; +// BEGIN +// rd.ReadVersion(minVersion, maxStoreVersion, thisVersion); +// IF ~rd.cancelled & s.isElem THEN +// rd.ReadVersion(minVersion, maxStoreVersion, thisVersion) +// (* works since maxStoreVersion = maxElemVersion = 0 in pre-1.3 *) +// END +// END Internalize; +// } + + /** + * PROCEDURE (s: Store) Externalize- (VAR wr: Writer) + * NEW, EMPTY + * (For backward compatibility, this method is actually still EXTENSIBLE. This may change in the future.) + * Write the contents of s to writer wr. Externalize must write the same (amount of) data as is read by the corresponding Internalize procedure. + * Externalize ist called locally. + * Externalize is extended by various persistent object types, e.g., models, views, and controllers. + */ + // FIXME + + /** + * PROCEDURE (s: Store) ExternalizeAs- (VAR s1: Store) + * NEW, EMPTY + * Before a store's Externalize procedure is called, its ExternalizeAs procedure is called, which gives the store the opportunity to denote another store that should be externalized in its place (a "proxy"). It is also possible to set s1 to NIL, which means that the store should not be externalized at all. This is used e.g. for compiler error markers, which are never stored. + * ExternalizeAs ist called locally. + * + * Pre + * s1 = s guaranteed + */ + // FIXME + }; + +} + +#endif // _STORE_H_ diff --git a/util.cc b/util.cc new file mode 100644 index 0000000..4f4b6c0 --- /dev/null +++ b/util.cc @@ -0,0 +1,15 @@ +#include + +namespace odc { + bool isBigEndian() { // http://stackoverflow.com/questions/1001307/detecting-endianness-programmatically-in-a-c-program + union { + uint32_t i; + uint8_t c[4]; + } test = {0x01020304}; + return test.c[0] == 1; + } + + bool isLittleEndian() { + return !isBigEndian(); + } +}