From: <sv...@ww...> - 2004-06-13 02:59:17
|
Author: mkrose Date: 2004-06-12 19:59:08 -0700 (Sat, 12 Jun 2004) New Revision: 1027 Added: trunk/CSP/SimData/Include/SimData/TaggedRecord.h trunk/CSP/SimData/Tools/TaggedRecordCompiler/ trunk/CSP/SimData/Tools/TaggedRecordCompiler/BaseTypes.py trunk/CSP/SimData/Tools/TaggedRecordCompiler/CodeFormat.py trunk/CSP/SimData/Tools/TaggedRecordCompiler/bootstrap.py trunk/CSP/SimData/Tools/TaggedRecordCompiler/trc.py Modified: trunk/CSP/SimData/CHANGES.current Log: Add tagged record compiler and related include files. Allows data record descriptions to be compiled into classes that hold the specified data and can be serialized into a tagged binary format. Modified: trunk/CSP/SimData/CHANGES.current =================================================================== --- trunk/CSP/SimData/CHANGES.current 2004-06-13 00:56:10 UTC (rev 1026) +++ trunk/CSP/SimData/CHANGES.current 2004-06-13 02:59:08 UTC (rev 1027) @@ -11,6 +11,8 @@ * Minor tweaks to unsigned Reader/Writer classes to used fixed size integers. + * Added tagged record compiler and associated header. + 2004-16-12: wolverine * added a MemoryWriter class to write out a SimData object to a binary memory buffer. Added a MemoryReader class. Added Added: trunk/CSP/SimData/Include/SimData/TaggedRecord.h =================================================================== --- trunk/CSP/SimData/Include/SimData/TaggedRecord.h 2004-06-13 00:56:10 UTC (rev 1026) +++ trunk/CSP/SimData/Include/SimData/TaggedRecord.h 2004-06-13 02:59:08 UTC (rev 1027) @@ -0,0 +1,332 @@ +#ifndef __SIMDATA_TRF_H__ +#define __SIMDATA_TRF_H__ + +#include <string> +#include <stack> +#include <vector> +#include <sstream> +#include <cassert> +#include <ostream> + +#include <SimData/Ref.h> +#include <SimData/Archive.h> +#include <SimData/Namespace.h> + +NAMESPACE_SIMDATA + +// use our own, platform-neutral int64 representation +// TODO the base class (hasht) should probably renamed. +typedef hasht int64; + + +/** + * Simple Writer class for serializing to a string buffer. + */ +class StringWriter: public Writer { + std::string _buffer; +public: + StringWriter() { + _buffer.reserve(1024); + } + virtual Writer & operator<<(char const x) { + _buffer.append(reinterpret_cast<const char*>(&x), sizeof(x)); + return *this; + } + virtual Writer & operator<<(int16 const x) { + _buffer.append(reinterpret_cast<const char*>(&x), sizeof(x)); + return *this; + } + virtual Writer & operator<<(int32 const x) { + _buffer.append(reinterpret_cast<const char*>(&x), sizeof(x)); + return *this; + } + virtual Writer & operator<<(int64 const x) { + _buffer.append(reinterpret_cast<const char*>(&x), sizeof(x)); + return *this; + } + virtual Writer & operator<<(uint8 const x) { + _buffer.append(reinterpret_cast<const char*>(&x), sizeof(x)); + return *this; + } + virtual Writer & operator<<(uint16 const x) { + _buffer.append(reinterpret_cast<const char*>(&x), sizeof(x)); + return *this; + } + virtual Writer & operator<<(uint32 const x) { + _buffer.append(reinterpret_cast<const char*>(&x), sizeof(x)); + return *this; + } + virtual Writer & operator<<(float const x) { + _buffer.append(reinterpret_cast<const char*>(&x), sizeof(x)); + return *this; + } + virtual Writer & operator<<(double const x) { + _buffer.append(reinterpret_cast<const char*>(&x), sizeof(x)); + return *this; + } + virtual Writer & operator<<(bool const x) { + _buffer.append(reinterpret_cast<const char*>(&x), sizeof(x)); + return *this; + } + virtual Writer & operator<<(hasht const &x) { + _buffer.append(reinterpret_cast<const char*>(&x), sizeof(x)); + return *this; + } + virtual Writer & operator<<(char const *x) { + assert(0); + return *this; + } + virtual Writer & operator<<(BaseType const &x) { + x.serialize(*this); + return *this; + } + virtual Writer & operator<<(std::string const &x) { + writeLength(x.size()); + _buffer.append(x); + return *this; + } + std::string str() const { + return _buffer; + } +}; + +/** + * Simple Reader class for serializing from a string buffer. + */ +class StringReader: public Reader { + const unsigned char *_data; + int _bytes; +public: + StringReader(std::string const &buffer) + : _data(reinterpret_cast<const unsigned char *>(buffer.data())), + _bytes(buffer.size()) { } + virtual Reader & operator>>(char &x) { + assert(_bytes >= sizeof(x)); + x = *(reinterpret_cast<char const*>(_data)); + _data += sizeof(x); + _bytes -= sizeof(x); + return *this; + } + virtual Reader & operator>>(int16 &x) { + assert(_bytes >= sizeof(x)); + x = *(reinterpret_cast<int16 const*>(_data)); + _data += sizeof(x); + _bytes -= sizeof(x); + return *this; + } + virtual Reader & operator>>(int32 &x) { + assert(_bytes >= sizeof(x)); + x = *(reinterpret_cast<int32 const*>(_data)); + _data += sizeof(x); + _bytes -= sizeof(x); + return *this; + } + virtual Reader & operator>>(int64 &x) { + assert(_bytes >= sizeof(x)); + x = *(reinterpret_cast<int64 const*>(_data)); + _data += sizeof(x); + _bytes -= sizeof(x); + return *this; + } + virtual Reader & operator>>(uint8 &x) { + assert(_bytes >= sizeof(x)); + x = *(reinterpret_cast<uint8 const*>(_data)); + _data += sizeof(x); + _bytes -= sizeof(x); + return *this; + } + virtual Reader & operator>>(uint16 &x) { + assert(_bytes >= sizeof(x)); + x = *(reinterpret_cast<uint16 const*>(_data)); + _data += sizeof(x); + _bytes -= sizeof(x); + return *this; + } + virtual Reader & operator>>(uint32 &x) { + assert(_bytes >= sizeof(x)); + x = *(reinterpret_cast<uint32 const*>(_data)); + _data += sizeof(x); + _bytes -= sizeof(x); + return *this; + } + virtual Reader & operator>>(float &x) { + assert(_bytes >= sizeof(x)); + x = *(reinterpret_cast<float const*>(_data)); + _data += sizeof(x); + _bytes -= sizeof(x); + return *this; + } + virtual Reader & operator>>(double &x) { + assert(_bytes >= sizeof(x)); + x = *(reinterpret_cast<double const*>(_data)); + _data += sizeof(x); + _bytes -= sizeof(x); + return *this; + } + virtual Reader & operator>>(bool &x) { + assert(_bytes >= sizeof(x)); + x = *(reinterpret_cast<bool const*>(_data)); + _data += sizeof(x); + _bytes -= sizeof(x); + return *this; + } + virtual Reader & operator>>(char * &x) { + assert(0); + return *this; + } + virtual Reader & operator>>(BaseType &x) { + x.serialize(*this); + return *this; + } + virtual Reader & operator>>(std::string &x) { + int length = readLength(); + assert(_bytes >= length); + x.clear(); + x.append(reinterpret_cast<const char*>(_data), length); + _data += length; + _bytes -= length; + return *this; + } +}; + + +/** + * Base class for TagWriter and TagReader which manages a stack + * of nested records. + */ +class TagBase { + protected: + std::stack<int> _tagstack; + enum { TAG_END = 0 }; + int _lasttag; + public: + TagBase(): _lasttag(0) { } +}; + + +/** + * Class for writing tagged records to wire format. + */ +class TagWriter: public TagBase { + public: + Writer &writer; + TagWriter(Writer &writer_): TagBase(), writer(writer_) { } + void writeTag(int tag) { + int delta = tag - _lasttag; + _lasttag = tag; + if (delta < 128) { + writer << static_cast<unsigned char>(delta); + } else { + unsigned char thi = static_cast<unsigned char>(delta >> 7); + unsigned char tlo = static_cast<unsigned char>(0x80 | (delta & 0x7f)); + writer << tlo << thi; + } + } + void beginCompound() { + _tagstack.push(_lasttag); + _lasttag = 0; + } + void endCompound() { + writer << static_cast<unsigned char>(TAG_END); + _lasttag = _tagstack.top(); + _tagstack.pop(); + } + void writeLength(int x) { + assert(x >= 0); + while (x >= 128) { + writer << static_cast<unsigned char>(0x80 | (x & 0x7f)); + x >>= 7; + } + writer << static_cast<unsigned char>(x); + } +}; + + +/** + * Class for reading tagged records from wire format. + */ +class TagReader: public TagBase { + public: + Reader &reader; + TagReader(Reader &reader_): TagBase(), reader(reader_) { } + int nextTag() { + uint8 ubyte; + reader >> ubyte; + if (ubyte == 0) { return 0; } + int delta = ubyte & 0x7f; + if (ubyte & 0x80) { + reader >> ubyte; + delta |= ubyte << 7; + } + _lasttag += delta; + return _lasttag; + } + void beginCompound() { + _tagstack.push(_lasttag); + _lasttag = 0; + } + void endCompound() { + _lasttag = _tagstack.top(); + _tagstack.pop(); + } + int readLength() { + int length = 0; + int sh = 0; + unsigned char x; + do { + reader >> x; + length |= (x & 0x7f) << sh; + sh += 7; + } while (x & 0x80); + return length; + } +}; + + +/** + * Base class for auto-generated record classes that can be serialized + * to a tagged binary format. Subclasses are generated by compiling + * record definitions with the TaggedRecordCompiler. + */ +class TaggedRecord: public Referenced { +public: + typedef int64 Id; + virtual void serialize(TagReader &reader) = 0; + virtual void serialize(TagWriter &writer) const = 0; + virtual Id getId() const=0; + virtual int getVersion() const=0; + virtual std::string getName() const=0; + virtual void dump(std::ostream &, int indent=0) const=0; +protected: + virtual ~TaggedRecord() {} +}; + + +// dump a human-readable representation of a TaggedRecord instance +inline std::ostream & operator << (std::ostream &os, TaggedRecord const &tr) { + tr.dump(os); + return os; +} + + +/** + * Small helper class for indenting TaggedRecord dumps. + */ +class Indent { +public: + int level; + Indent(int level_=0): level(level_) {} + Indent & operator++() { ++level; return *this; } + Indent & operator--() { --level; return *this; } +}; + +std::ostream & operator << (std::ostream &os, Indent const &indent) { + for (int i = 0; i < indent.level; ++i) os << " "; + return os; +} + + +NAMESPACE_SIMDATA_END + +#endif // __SIMDATA_TRF_H__ + Added: trunk/CSP/SimData/Tools/TaggedRecordCompiler/BaseTypes.py =================================================================== --- trunk/CSP/SimData/Tools/TaggedRecordCompiler/BaseTypes.py 2004-06-13 00:56:10 UTC (rev 1026) +++ trunk/CSP/SimData/Tools/TaggedRecordCompiler/BaseTypes.py 2004-06-13 02:59:08 UTC (rev 1027) @@ -0,0 +1,644 @@ +# SimData: Data Infrastructure for Simulations +# Copyright 2004 Mark Rose <mk...@us...> +# +# This file is part of SimData. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +""" +Data types supported by the trf format. +""" + +import sys + +import CodeFormat + +import md5 +def md5hash(s): + """return a 64-bit (python long) hash of a string""" + return long(md5.md5(s).hexdigest()[:16], 16) + + +class Declaration: + DEFAULT = 0 + COMPOUND = 0 + MULTIPLE = 0 + TOPLEVEL = 0 + ANONYMOUS = 0 + TYPEDEF = 0 + ANONYMOUS_COUNT = {} + DELETE = 0 + POINTER = 0 + + def __init__(self, id, opts=None, name=None): + if id is None: id = '' + anon = self.__class__.ANONYMOUS + if anon: + assert id == '' + count = Declaration.ANONYMOUS_COUNT.setdefault(anon, 0) + id = '%s%d' % (anon, count) + Declaration.ANONYMOUS_COUNT[anon] = count + 1 + if not self.__class__.DEFAULT: + assert opts is None or not opts.has_key('DEFAULT') + self.id = id + self.opts = opts + self.child = None + self.elements = [] + self.localtypes = {} + self.name = name + self.init() + + def dump_init(self, format, comma): + text = '%s(%s)' % (self.varname(), self.default()) + if comma: text = text + ',' + format.write(text) + + def dump_clear(self, format): + format.write('void clear_%s() { m_has_%s = 0; }' % (self.id, self.id)) + + def init(self): pass + def dump_private(self, format): assert 0 + def dump_public(self, format): assert 0 + def dump_delete(self, format): assert 0 + def dump_save(self, format): assert 0 + def dump_load(self, format): assert 0 + def dump_print(self, format): assert 0 + def default(self): + if self.isPointer(): return 'NULL' + return self.opts.get('DEFAULT', '') + def fulltype(self): + typename = self.typename() + if self.isPointer(): typename = 'simdata::Ref<%s>' % typename + return typename + def typename(self): return self.__class__.TYPENAME + def isTypedef(self): return self.__class__.TYPEDEF + def needsDelete(self): return self.__class__.DELETE + def isPointer(self): return self.__class__.POINTER + def isCompound(self): return self.__class__.COMPOUND + def isDeprecated(self): return self.opts.get('DEPRECATED', 0) + def varname(self): + if self.name: return self.name + return 'm_' + self.id + + +class CompoundType(Declaration): + COMPOUND = 1 + + def add(self, element): + if element.isTypedef(): + self.localtypes[element.id] = element + else: + self.elements.append(element) + + def classdef(self, format, base=None): + format.write() + if base is None: + format.write('class %s {' % (self.id)) + else: + format.write('class %s: public %s {' % (self.id, base)) + if self.localtypes: + format.write('public:') + format.write() + format.indent() + for typedef in self.localtypes.values(): + typedef.dump(format) + format.write() + format.dedent() + format.write() + format.write('private:') + format.write() + format.indent() + if self.elements: + format.write('enum {') + format.indent() + idx = 8 + for element in self.elements: + format.write('TAG_%s = %d,' % (element.id, idx)) + idx = idx + 1 + format.dedent() + format.write('};') + format.write() + for element in self.elements: + format.write('simdata::int32 m_has_%s : 1;' % (element.id)) + format.write() + for element in self.elements: + element.dump_private(format); + format.dedent() + format.write() + format.write('public:') + format.write() + format.indent() + if self.elements: + format.write('%s():' % self.id) + format.indent() + for idx, element in enumerate(self.elements): + format.write('m_has_%s(0),' % element.id) + comma = (idx + 1) < len(self.elements) + element.dump_init(format, comma) + format.dedent() + format.write('{ }') + format.write() + deletes = [x for x in self.elements if x.needsDelete()] + if deletes: + format.write('~%s() {' % self.id) + format.indent() + for delete in deletes: + delete.dump_delete(format) + format.dedent() + format.write('}') + format.write() + for element in self.elements: + format.write('bool has_%s() const { return m_has_%s; }' % (element.id, element.id)) + element.dump_clear(format) + format.write() + for element in self.elements: + element.dump_public(format); + format.write() + self._declaration(format) + format.dedent() + format.write('public:') + format.indent() + self._save(format) + self._load(format) + self._print(format) + self._extra(format) + format.dedent() + format.write('};') + format.write() + + def _declaration(self, format): + pass + + def _save(self, format): + format.write('void serialize(simdata::TagWriter &writer) const {') + format.indent() + format.write('writer.beginCompound();') + for element in self.elements: + format.write('if (m_has_%s) {' % element.id) + format.indent() + format.write('writer.writeTag(TAG_%s);' % element.id) + element.dump_save(format) + format.dedent() + format.write('}') + format.write('writer.endCompound();') + format.dedent() + format.write('}') + + def _load(self, format): + format.write('void serialize(simdata::TagReader &reader) {') + format.indent() + format.write('reader.beginCompound();') + format.write('while (1) {') + format.indent() + format.write('int tag = reader.nextTag();') + format.write('if (!tag) break;') + format.write('switch (tag) {') + for element in self.elements: + format.write('case TAG_%s: {' % element.id) + format.indent() + format.write('m_has_%s = 1;' % element.id) + element.dump_load(format) + format.write('break; }') + format.dedent() + format.write('default: break;') + format.write('}') + format.dedent() + format.write('}') + format.write('reader.endCompound();') + format.dedent() + format.write('}') + + def _print(self, format): + format.write('void dump(std::ostream &os, int level=0) const {') + format.indent() + format.write('simdata::Indent indent(level);') + format.write('os << indent << "%s <\\n";' % self.id) + format.write('++indent;') + for element in self.elements: + format.write('if (m_has_%s) {' % element.id) + format.indent() + format.write('os << indent << "%s: ";' % element.id) + element.dump_print(format) + format.write('os << "\\n";') + format.dedent() + format.write('}') + format.write('--indent;') + format.write('os << indent << ">";') + format.dedent() + format.write('}') + + def _extra(self, format): + pass + + def dump_save(self, format): + if self.isPointer(): + format.write('%s->serialize(writer);' % self.varname()) + else: + format.write('%s.serialize(writer);' % self.varname()) + + def dump_load(self, format): + if self.isPointer(): + type = self.typename() + format.write('%s = new %s();' % (self.varname(), type)) + format.write('%s->serialize(reader);' % self.varname()) + else: + format.write('%s.serialize(reader);' % self.varname()) + + def dump_print(self, format): + if self.isPointer(): + format.write('%s->dump(os, indent.level);' % self.varname()) + else: + format.write('%s.dump(os, indent.level);' % self.varname()) + + +class SimpleType(Declaration): + DEFAULT = 1 + + CT_SET = ''' + void set_%(id)s(%(type)s const & value) { + >m_has_%(id)s = true; + >m_%(id)s = value; + } + ''' + + def dump_private(self, format): + self.dump_decl(format) + + def dump_public(self, format): + self.dump_get(format) + self.dump_set(format) + + def dump_decl(self, format): + type = self.typename() + format.write('%s %s;' % (type, self.varname())) + + def dump_get(self, format): + type = self.typename() + id = self.id + format.write('%s const & %s() const { return m_%s; }' % (type, id, id)) + + def dump_set(self, format): + if self.isDeprecated(): return + d = {'id': self.id, 'type': self.typename()} + format.template(SimpleType.CT_SET, d) + return + type = self.typename() + id = self.id + format.write('void set_%s(%s const &value) {' % (id, type)) + format.indent() + format.write('m_has_%s = true;' % (id)) + format.write('%s = value;' % self.varname()) + format.dedent() + format.write('}') + + def dump_save(self, format): + format.write('writer.writer << %s;' % self.varname()) + + def dump_load(self, format): + format.write('reader.reader >> %s;' % self.varname()) + + def dump_print(self, format): + format.write('os << %s;' % self.varname()) + + +class ArrayType(Declaration): + + def __init__(self, id, childtype, opts=None): + Declaration.__init__(self, id, opts=opts) + self.child = childtype(id, name='%s[i]' % self.varname()) + + CT_SET = ''' + std::vector< %(type)s > & set_%(id)s() { + >m_has_%(id)s = true; + >return %(name)s; + } + ''' + + def dump_private(self, format): + self.dump_decl(format) + + def dump_public(self, format): + self.dump_get(format) + self.dump_set(format) + + def dump_decl(self, format): + type = self.child.fulltype() + format.write('std::vector< %s > %s;' % (type, self.varname())) + + def dump_clear(self, format): + format.write('void clear_%s() {' % self.id) + format.indent() + format.write('m_has_%s = 0;' % self.id) + format.write('%s.clear();' % self.varname()) + format.dedent() + format.write('}') + + def dump_get(self, format): + type = self.child.fulltype() + id = self.id + name = self.varname() + format.write('std::vector< %s > const & %s() const { return %s; }' % (type, id, name)) + + def dump_set(self, format): + if self.isDeprecated(): return + type = self.child.fulltype() + d = {'id': self.id, 'type': type, 'name': self.varname()} + format.template(ArrayType.CT_SET, d) + + def dump_save(self, format): + format.write('writer.writeLength(%s.size());' % self.varname()) + format.write('for (int i=0; i < %s.size(); ++i) {' % self.varname()) + format.indent() + self.child.dump_save(format) + format.dedent() + format.write('}') + + def dump_load(self, format): + format.write('int %s_len = reader.readLength();' % self.id) + format.write('%s.resize(%s_len);' % (self.varname(), self.id)) + format.write('for (int i=0; i < %s_len; ++i) {' % self.id) + format.indent() + self.child.dump_load(format) + format.dedent() + format.write('}') + + def dump_print(self, format): + format.write('os << "[\\n";') + format.write('++indent;') + format.write('for (int i=0; i < %s.size(); ++i) {' % self.varname()) + format.indent() + self.child.dump_print(format) + format.write('os << "\\n";') + format.dedent() + format.write('}') + format.write('--indent;') + format.write('os << "]";') + + +class TrfType(SimpleType): + def typename(self): + return 'simdata::' + SimpleType.typename(self) + + +class Message(CompoundType): + DEFAULT = 0 + MULTIPLE = 0 + TOPLEVEL = 1 + TYPEDEF = 0 + POINTER = 1 + DELETE = 0 + TYPENAME = 'Message' + + def __call__(self, id, opts=None, name=None): + message = Message(id, opts=opts, name=name) + message.TYPENAME = self.id + return message + + def typename(self): return self.TYPENAME + + def dump(self, format=None, file=file): + if not format: + format = CodeFormat.Format(file=file) + base = self.opts.get('BASE', 'simdata::TaggedRecord') + self.classdef(format, base) + + def _extra(self, format): + CompoundType._extra(self, format) + name = self.id + try: + version = int(self.opts.get('VERSION', 0)) + except ValueError: + print >>sys.stderr, 'ERROR: VERSION option on %s must be an integer' % name + sys.exit(1) + id = md5hash('%s_%d' % (name, version)) + d = {'name': name, 'version': version, 'id': id} + format.template(Message.TRF_GETID, d) + format.template(Message.TRF_GETVERSION, d) + format.template(Message.TRF_GETNAME, d) + + def dump_private(self, format): + format.write('simdata::Ref<%s> %s;' % (self.typename(), self.varname())) + + def dump_public(self, format): + d = {'id': self.id, 'name': self.varname(), 'type': self.typename()} + format.template(Message.TRF_GET, d) + format.template(Message.TRF_SET, d) + + TRF_GETID = ''' + virtual Id getId() const { return _getId(); } + static inline Id _getId() { return %(id)dll; } + ''' + + TRF_GETVERSION = ''' + virtual int getVersion() const { return _getVersion(); } + static inline int _getVersion() { return %(version)d; } + ''' + + TRF_GETNAME = ''' + virtual std::string getName() const { return _getName(); } + static inline std::string _getName() { return "%(name)s"; } + ''' + + def dump_delete(self, format): + format.write('delete %s;' % self.varname()) + + def _declaration(self, format): + pass + + TRF_SET = ''' + simdata::Ref<%(type)s> & set_%(id)s() { + >m_has_%(id)s = 1; + >if (%(name)s.isNull()) %(name)s = new %(type)s(); + >return %(name)s; + } + ''' + + TRF_GET = ''' + simdata::Ref<%(type)s> const & %(id)s() const { + >return %(name)s; + } + ''' + + +class Group(CompoundType): + TYPENAME = 'group' + TYPEDEF = 1 + + def add(self, element): + self.elements.append(element); + + def dump(self, format): + self.classdef(format, base='simdata::Referenced') + + def __call__(self, id, opts=None, name=None): + return GroupDeclaration(self.id, id, opts=opts, name=name) + + +class GroupDeclaration(CompoundType): + DELETE = 0 + POINTER = 1 + + TRF_DECL = ''' + simdata::Ref<%(type)s> m_%(id)s; + ''' + + TRF_SET = ''' + simdata::Ref<%(type)s> & set_%(id)s() { + >m_has_%(id)s = 1; + >if (m_%(id)s.isNull()) m_%(id)s = new %(type)s(); + >return m_%(id)s; + } + ''' + + TRF_GET = ''' + simdata::Ref<%(type)s> const & %(id)s() const { + >return m_%(id)s; + } + ''' + + def __init__(self, typename, id, opts=None, name=None): + CompoundType.__init__(self, id, opts=opts, name=name) + self._typename = typename + + def typename(self): return self._typename + + def dump_private(self, format): + d = {'id': self.id, 'type': self._typename} + format.template(GroupDeclaration.TRF_DECL, d) + + def dump_public(self, format): + d = {'id': self.id, 'type': self._typename} + format.template(GroupDeclaration.TRF_GET, d) + format.template(GroupDeclaration.TRF_SET, d) + + def dump_delete(self, format): + format.write('delete %s;' % self.varname()) + + +class Bitset(CompoundType): + TYPENAME = 'bitset' + ANONYMOUS = 'bitset' + + def add(self, element): + assert element.TYPENAME == 'bool' + assert len(self.elements) < 32 + self.elements.append(element); + + def default(self): + value = 0 + mask = 1 + for bool in self.elements: + if int(bool.default()): + value |= mask + mask <<= 1 + return '0x%08x' % value + + def dump_private(self, format): + width = 32 + format.write('simdata::int%d %s;' % (width, self.varname())) + + def dump_get(self, format): + mask = 1 + for bool in self.elements: + format.write('bool %s() const {' % bool.id) + format.indent() + format.write('return (%s & 0x%08x) != 0;' % (self.varname(), mask)) + format.dedent() + format.write('}') + mask = mask << 1 + + def dump_set(self, format): + mask = 1 + id = self.id + name = self.varname() + for bool in self.elements: + if not bool.isDeprecated(): + format.write('void set_%s(bool state) {' % bool.id) + format.indent() + format.write('m_has_%s = true;' % id); + format.write('%s = state ? (%s | 0x%08x) : (%s & ~0x%08x);' % (name, name, mask, name, mask)) + format.dedent() + format.write('}') + mask = mask << 1 + + def dump_public(self, format): + self.dump_get(format) + self.dump_set(format) + + def dump_save(self, format): + format.write('writer.writer << %s;' % self.varname()) + + def dump_load(self, format): + format.write('reader.reader >> %s;' % self.varname()) + + def dump_print(self, format): + for bool in self.elements: + format.write('os << indent << "%s: " << "\\n";' % bool.id) + +class t_bool(SimpleType): TYPENAME = 'bool' +class t_float(SimpleType): TYPENAME = 'float' +class t_double(SimpleType): TYPENAME = 'double' +class t_int64(TrfType): TYPENAME = 'int64' +class t_int32(TrfType): TYPENAME = 'int32' +class t_int16(TrfType): TYPENAME = 'int16' +class t_int8(TrfType): TYPENAME = 'int8' +class t_string(SimpleType): TYPENAME = 'std::string' + + +class SimDataType(SimpleType): + def typename(self): + return SimpleType.typename(self) + +class t_Matrix3(SimDataType): TYPENAME = 'simdata::Matrix3' +class t_Quat(SimDataType): TYPENAME = 'simdata::Quat' +class t_Vector3(SimDataType): TYPENAME = 'simdata::Vector3' +class t_Key(SimDataType): TYPENAME = 'simdata::Key' +class t_Date(SimDataType): TYPENAME = 'simdata::SimDate' +class t_Path(SimDataType): TYPENAME = 'simdata::Path' + +#class t_TimeStamp(SimDataType): TYPENAME = 'TimeStamp' +#class t_Vector3f(SimDataType): TYPENAME = 'Vector3f' +#class t_Quatf(SimDataType): TYPENAME = 'Quatf' + +TYPES = [Message, Bitset, Group] + +TYPES.extend([ + t_float, + t_double, + t_int64, + t_int32, + t_int16, + t_int8, + t_bool, + t_string, +]) + +TYPES.extend([ + t_Matrix3, + t_Quat, + t_Vector3, + t_Key, + t_Date, + t_Path, +]) + +TYPEMAP = {} + +def RegisterType(type): + global TYPEMAP + TYPEMAP[type.TYPENAME] = type + +map(RegisterType, TYPES) + Added: trunk/CSP/SimData/Tools/TaggedRecordCompiler/CodeFormat.py =================================================================== --- trunk/CSP/SimData/Tools/TaggedRecordCompiler/CodeFormat.py 2004-06-13 00:56:10 UTC (rev 1026) +++ trunk/CSP/SimData/Tools/TaggedRecordCompiler/CodeFormat.py 2004-06-13 02:59:08 UTC (rev 1027) @@ -0,0 +1,64 @@ +# SimData: Data Infrastructure for Simulations +# Copyright 2004 Mark Rose <mk...@us...> +# +# This file is part of SimData. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +""" +Helper class for formatting nested output. +""" + +import sys + +class Format: + + def __init__(self, file=None, indent=''): + if file is None: + file = sys.stdout + self._file = file + self._indent = indent + + def indent(self): + self._indent = self._indent + ' ' + + def dedent(self): + self._indent = self._indent[:-2] + + def write(self, text=''): + if text: + print >>self._file, '%s%s' % (self._indent, text) + else: + print >>self._file + + def template(self, template, dict): + template = template % dict + n = 0 + for line in template.split('\n'): + n += 1 + line = line.strip() + if not line: continue + if line == '.': + self.write(); + continue + indent = 0 + istr = '' + while indent < len(line) and line[indent] == '>': + indent += 1 + istr += ' ' + line = istr + line[indent:] + if line: + self.write(line) + Added: trunk/CSP/SimData/Tools/TaggedRecordCompiler/bootstrap.py =================================================================== --- trunk/CSP/SimData/Tools/TaggedRecordCompiler/bootstrap.py 2004-06-13 00:56:10 UTC (rev 1026) +++ trunk/CSP/SimData/Tools/TaggedRecordCompiler/bootstrap.py 2004-06-13 02:59:08 UTC (rev 1027) @@ -0,0 +1,33 @@ +# SimData: Data Infrastructure for Simulations +# Copyright 2004 Mark Rose <mk...@us...> +# +# This file is part of SimData. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +try: + import CSP +except: + import sys + import os.path + dn = os.path.dirname + csp_root = dn(dn(dn(dn(dn(__file__))))) + sys.path.insert(0, csp_root) + try: + import CSP + except: + print 'Unable to import the main CSP module. Check that you have' + print 'a complete working copy.' + sys.exit(1) Added: trunk/CSP/SimData/Tools/TaggedRecordCompiler/trc.py =================================================================== --- trunk/CSP/SimData/Tools/TaggedRecordCompiler/trc.py 2004-06-13 00:56:10 UTC (rev 1026) +++ trunk/CSP/SimData/Tools/TaggedRecordCompiler/trc.py 2004-06-13 02:59:08 UTC (rev 1027) @@ -0,0 +1,200 @@ +#!/usr/bin/python +# +# SimData: Data Infrastructure for Simulations +# Copyright 2004 Mark Rose <mk...@us...> +# +# This file is part of SimData. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +""" +Standalone compiler for converting tagged record descriptions +into C++ classes. + +Usage: %(prog)s [options] infile +""" + +import sys +import os +import os.path +import re + +import bootstrap +from CSP.base import app + +import BaseTypes + + +HEADER="""// generated file --- do not edit!' + +#ifndef __%(module_uc)s_TRF_H__ +#define __%(module_uc)s_TRF_H__ + +#include <SimData/TaggedRecord.h> +%(includes)s +""" + +FOOTER = """ +#endif // __%(module_uc)s_TRF_H__ +""" + + +class DataPackCompiler: + + re_line = re.compile(r'^(\w*:?:?\w+)(\[\])?\s+(\w*)\s*((?:\s+\w+\s*=\s*\w+)*)\s*({|})?$') + re_opts = re.compile(r'\s*=\s*') + re_ns = re.compile(r'namespace\s+([a-zA-Z_][a-zA-Z0-9]*)\s*;?') + + class Node: + pass + + def __init__(self, file, outfile): + self._root = None + self._active = None + self._outfile = outfile + self._parse(file) + + def _parse(self, source): + module = os.path.basename(source) + module = os.path.splitext(module)[0] + module = module.replace('.', '_') + self.source = source + file = open(source) + line_number = 0 + depth = 0 + dp = DataPackCompiler + object = None + object_stack = [] + toplevel = [] + toplevel_types = {} + includes = [] + namespace = '' + header = 1 + for line in file: + line_number = line_number + 1 + trim = line.strip() + if not trim: continue + if header and trim.startswith('#include'): + includes.append(trim) + continue + if header and trim.startswith('namespace'): + m = DataPackCompiler.re_ns.match(trim) + if m: + if namespace: self.error('multiple namespace declarations') + namespace = m.groups(1) + continue + else: + self.error('syntax error') + if trim.startswith('//'): + continue + header = 0 + while trim: + rest = '' + idx1 = trim.find('{') + idx2 = trim.find(';') + if idx1 >= 0 and (idx2 < 0 or idx2 > idx1): + rest = trim[idx1+1:].strip() + trim = trim[:idx1+1].strip() + elif idx2 >= 0: + rest = trim[idx2+1:].strip() + trim = trim[:idx2].strip() + while trim.startswith('}'): + if depth < 1: + self.error(line_number, 'unmatched brace') + depth = depth - 1 + object_stack = object_stack[:-1] + trim = trim[1:] + if not trim: + trim = rest + continue + m = dp.re_line.match(trim) + if m is None: + print trim + self.error(line_number, 'invalid syntax.') + type, array, id, options, block = m.groups() + if type is None: + self.error(line_number, 'invalid syntax (no type)') + type_class = None + if object_stack: + parent = object_stack[-1] + type_class = parent.localtypes.get(type, None) + if type_class is None: + type_class = BaseTypes.TYPEMAP.get(type, None) + if type_class is None: + type_class = toplevel_types.get(type, None) + if type_class is None: + self.error(line_number, 'unknown data type "%s"' % type) + if not id and not type_class.ANONYMOUS: + self.error(line_number, 'invalid syntax (unnamed field)') + if options is not None: + options = dp.re_opts.sub('=', options).strip() + option_list = options.split() + options = {} + for option_pair in option_list: + option, value = option_pair.split('=') + options[option] = value + if array: + object = BaseTypes.ArrayType(id, type_class, opts=options) + else: + object = type_class(id, opts=options) + if len(object_stack) > 0: + object_stack[-1].add(object) + else: + if not type_class.TOPLEVEL: + self.error(line_number, 'syntax error') + toplevel.append(object) + toplevel_types[id] = object + if block is not None: + if block == '{': + # TODO check that type supports blocks + depth = depth + 1 + object_stack.append(object) + else: + if depth < 1: + self.error(line_number, 'unmatched brace') + depth = depth - 1 + object_stack = object_stack[:-1] + trim = rest + if depth > 0: + self.error(line_number, 'unmatched brace') + includes = '\n'.join(includes) + values = {'module_uc': module.upper(), 'module': module, 'includes': includes}; + print >>self._outfile, HEADER % values + if namespace: print >>self._outfile, 'namespace %s {' % namespace + [x.dump(file=self._outfile) for x in toplevel] + if namespace: print >>self._outfile, '} // namespace %s' % namespace + print >>self._outfile, FOOTER % values + + def error(self, line_number, msg): + print >>sys.stderr, 'line %d: %s' % (line_number, msg) + sys.exit(1) + + +def main(args): + if len(args) != 1: + app.usage() + return 1 + output = app.options.output + if output: + outfile = open(output, 'wt') + else: + outfile = sys.stdout + file = args[0] + DataPackCompiler(file, outfile) + return 0 + +app.addOption('-o', '--output', metavar='FILE', default='', help='output file (default stdout)') +app.start() + Property changes on: trunk/CSP/SimData/Tools/TaggedRecordCompiler/trc.py ___________________________________________________________________ Name: svn:executable + * |