binpac: Reformat C++ code in Spicy style

This commit is contained in:
Tim Wojtulewicz 2023-10-30 13:15:14 -07:00
parent 716bf016a1
commit 3297de477b
89 changed files with 7887 additions and 9733 deletions

View file

@ -1,28 +1,24 @@
#ifndef binpac_an_h #ifndef binpac_an_h
#define binpac_an_h #define binpac_an_h
namespace binpac namespace binpac {
{
// TODO: Add the Done() function // TODO: Add the Done() function
// The interface for a connection analyzer // The interface for a connection analyzer
class ConnectionAnalyzer class ConnectionAnalyzer {
{
public: public:
virtual ~ConnectionAnalyzer() { } virtual ~ConnectionAnalyzer() {}
virtual void NewData(bool is_orig, const unsigned char* begin_of_data, virtual void NewData(bool is_orig, const unsigned char* begin_of_data, const unsigned char* end_of_data) = 0;
const unsigned char* end_of_data) = 0; };
};
// The interface for a flow analyzer // The interface for a flow analyzer
class FlowAnalyzer class FlowAnalyzer {
{
public: public:
virtual ~FlowAnalyzer() { } virtual ~FlowAnalyzer() {}
virtual void NewData(const unsigned char* begin_of_data, const unsigned char* end_of_data) = 0; virtual void NewData(const unsigned char* begin_of_data, const unsigned char* end_of_data) = 0;
}; };
} // namespace binpac } // namespace binpac
#endif // binpac_an_h #endif // binpac_an_h

View file

@ -7,310 +7,248 @@
#include "binpac.h" #include "binpac.h"
#include "binpac_buffer.h" #include "binpac_buffer.h"
namespace binpac namespace binpac {
{
extern double network_time(); extern double network_time();
namespace namespace {
{
const unsigned char CR = '\r'; const unsigned char CR = '\r';
const unsigned char LF = '\n'; const unsigned char LF = '\n';
} } // namespace
binpac::FlowBuffer::Policy binpac::FlowBuffer::policy = { binpac::FlowBuffer::Policy binpac::FlowBuffer::policy = {
// max_capacity // max_capacity
10 * 1024 * 1024, 10 * 1024 * 1024,
// min_capacity // min_capacity
512, 512,
// contract_threshold // contract_threshold
2 * 1024 * 1024, 2 * 1024 * 1024,
}; };
FlowBuffer::FlowBuffer(LineBreakStyle linebreak_style) FlowBuffer::FlowBuffer(LineBreakStyle linebreak_style) {
{ buffer_length_ = 0;
buffer_length_ = 0; buffer_ = nullptr;
buffer_ = nullptr;
orig_data_begin_ = nullptr; orig_data_begin_ = nullptr;
orig_data_end_ = nullptr; orig_data_end_ = nullptr;
linebreak_style_ = linebreak_style; linebreak_style_ = linebreak_style;
linebreak_style_default = linebreak_style; linebreak_style_default = linebreak_style;
linebreaker_ = 0; linebreaker_ = 0;
ResetLineState(); ResetLineState();
mode_ = UNKNOWN_MODE; mode_ = UNKNOWN_MODE;
frame_length_ = 0; frame_length_ = 0;
chunked_ = false; chunked_ = false;
data_seq_at_orig_data_end_ = 0; data_seq_at_orig_data_end_ = 0;
eof_ = false; eof_ = false;
have_pending_request_ = false; have_pending_request_ = false;
buffer_n_ = 0; buffer_n_ = 0;
NewMessage(); NewMessage();
} }
FlowBuffer::~FlowBuffer() FlowBuffer::~FlowBuffer() {
{ if ( buffer_ )
if ( buffer_ ) free(buffer_);
free(buffer_); }
}
void FlowBuffer::NewMessage() void FlowBuffer::NewMessage() {
{ BINPAC_ASSERT(frame_length_ >= 0);
BINPAC_ASSERT(frame_length_ >= 0);
int bytes_to_advance = 0; int bytes_to_advance = 0;
if ( buffer_n_ == 0 ) if ( buffer_n_ == 0 ) {
{ switch ( mode_ ) {
switch ( mode_ ) case LINE_MODE: bytes_to_advance = (frame_length_ + (linebreak_style_ == STRICT_CRLF ? 2 : 1)); break;
{ case FRAME_MODE: bytes_to_advance = frame_length_; break;
case LINE_MODE: case UNKNOWN_MODE: break;
bytes_to_advance = (frame_length_ + (linebreak_style_ == STRICT_CRLF ? 2 : 1)); }
break; }
case FRAME_MODE:
bytes_to_advance = frame_length_;
break;
case UNKNOWN_MODE:
break;
}
}
orig_data_begin_ += bytes_to_advance; orig_data_begin_ += bytes_to_advance;
BINPAC_ASSERT(orig_data_begin_ <= orig_data_end_); BINPAC_ASSERT(orig_data_begin_ <= orig_data_end_);
buffer_n_ = 0; buffer_n_ = 0;
message_complete_ = false; message_complete_ = false;
ContractBuffer(); ContractBuffer();
} }
void FlowBuffer::ResetLineState() void FlowBuffer::ResetLineState() {
{ switch ( linebreak_style_ ) {
switch ( linebreak_style_ ) case CR_OR_LF: state_ = CR_OR_LF_0; break;
{ case STRICT_CRLF: state_ = STRICT_CRLF_0; break;
case CR_OR_LF: case LINE_BREAKER: break; // Nothing to reset
state_ = CR_OR_LF_0; default: BINPAC_ASSERT(0); break;
break; }
case STRICT_CRLF: }
state_ = STRICT_CRLF_0;
break;
case LINE_BREAKER:
break; // Nothing to reset
default:
BINPAC_ASSERT(0);
break;
}
}
void FlowBuffer::ExpandBuffer(int length) void FlowBuffer::ExpandBuffer(int length) {
{ if ( buffer_length_ >= length )
if ( buffer_length_ >= length ) return;
return;
if ( length < policy.min_capacity ) if ( length < policy.min_capacity )
length = policy.min_capacity; length = policy.min_capacity;
if ( length < buffer_length_ * 2 ) if ( length < buffer_length_ * 2 )
length = buffer_length_ * 2; length = buffer_length_ * 2;
if ( length > policy.max_capacity ) if ( length > policy.max_capacity ) {
{ std::string reason = strfmt("expand past max capacity %d/%d", length, policy.max_capacity);
std::string reason = strfmt("expand past max capacity %d/%d", length, policy.max_capacity); throw ExceptionFlowBufferAlloc(reason.c_str());
throw ExceptionFlowBufferAlloc(reason.c_str()); }
}
// Allocate a new buffer and copy the existing contents // Allocate a new buffer and copy the existing contents
buffer_length_ = length; buffer_length_ = length;
unsigned char* new_buf = (unsigned char*)realloc(buffer_, buffer_length_); unsigned char* new_buf = (unsigned char*)realloc(buffer_, buffer_length_);
if ( ! new_buf ) if ( ! new_buf )
throw ExceptionFlowBufferAlloc("expand realloc OOM"); throw ExceptionFlowBufferAlloc("expand realloc OOM");
buffer_ = new_buf; buffer_ = new_buf;
} }
void FlowBuffer::ContractBuffer() void FlowBuffer::ContractBuffer() {
{ if ( buffer_length_ < policy.contract_threshold )
if ( buffer_length_ < policy.contract_threshold ) return;
return;
buffer_length_ = policy.min_capacity; buffer_length_ = policy.min_capacity;
unsigned char* new_buf = (unsigned char*)realloc(buffer_, buffer_length_); unsigned char* new_buf = (unsigned char*)realloc(buffer_, buffer_length_);
if ( ! new_buf ) if ( ! new_buf )
throw ExceptionFlowBufferAlloc("contract realloc OOM"); throw ExceptionFlowBufferAlloc("contract realloc OOM");
buffer_ = new_buf; buffer_ = new_buf;
} }
void FlowBuffer::SetLineBreaker(unsigned char* lbreaker) void FlowBuffer::SetLineBreaker(unsigned char* lbreaker) {
{ linebreaker_ = *lbreaker;
linebreaker_ = *lbreaker; linebreak_style_default = linebreak_style_;
linebreak_style_default = linebreak_style_; linebreak_style_ = LINE_BREAKER;
linebreak_style_ = LINE_BREAKER; }
}
void FlowBuffer::UnsetLineBreaker() void FlowBuffer::UnsetLineBreaker() { linebreak_style_ = linebreak_style_default; }
{
linebreak_style_ = linebreak_style_default;
}
void FlowBuffer::NewLine() void FlowBuffer::NewLine() {
{ FlowBuffer::NewMessage();
FlowBuffer::NewMessage(); mode_ = LINE_MODE;
mode_ = LINE_MODE; frame_length_ = 0;
frame_length_ = 0; chunked_ = false;
chunked_ = false; have_pending_request_ = true;
have_pending_request_ = true; if ( state_ == FRAME_0 )
if ( state_ == FRAME_0 ) ResetLineState();
ResetLineState(); MarkOrCopyLine();
MarkOrCopyLine(); }
}
void FlowBuffer::NewFrame(int frame_length, bool chunked) void FlowBuffer::NewFrame(int frame_length, bool chunked) {
{ FlowBuffer::NewMessage();
FlowBuffer::NewMessage(); mode_ = FRAME_MODE;
mode_ = FRAME_MODE; frame_length_ = frame_length;
frame_length_ = frame_length; chunked_ = chunked;
chunked_ = chunked; have_pending_request_ = true;
have_pending_request_ = true; MarkOrCopyFrame();
MarkOrCopyFrame(); }
}
void FlowBuffer::BufferData(const_byteptr data, const_byteptr end) void FlowBuffer::BufferData(const_byteptr data, const_byteptr end) {
{ mode_ = FRAME_MODE;
mode_ = FRAME_MODE; frame_length_ += (end - data);
frame_length_ += (end - data); MarkOrCopyFrame();
MarkOrCopyFrame(); NewData(data, end);
NewData(data, end); }
}
void FlowBuffer::FinishBuffer() void FlowBuffer::FinishBuffer() { message_complete_ = true; }
{
message_complete_ = true;
}
void FlowBuffer::GrowFrame(int length) void FlowBuffer::GrowFrame(int length) {
{ BINPAC_ASSERT(frame_length_ >= 0);
BINPAC_ASSERT(frame_length_ >= 0); if ( length <= frame_length_ )
if ( length <= frame_length_ ) return;
return; BINPAC_ASSERT(! chunked_ || frame_length_ == 0);
BINPAC_ASSERT(! chunked_ || frame_length_ == 0); mode_ = FRAME_MODE;
mode_ = FRAME_MODE; frame_length_ = length;
frame_length_ = length; MarkOrCopyFrame();
MarkOrCopyFrame(); }
}
void FlowBuffer::DiscardData() void FlowBuffer::DiscardData() {
{ mode_ = UNKNOWN_MODE;
mode_ = UNKNOWN_MODE; message_complete_ = false;
message_complete_ = false; have_pending_request_ = false;
have_pending_request_ = false; orig_data_begin_ = orig_data_end_ = nullptr;
orig_data_begin_ = orig_data_end_ = nullptr;
buffer_n_ = 0; buffer_n_ = 0;
frame_length_ = 0; frame_length_ = 0;
ContractBuffer(); ContractBuffer();
} }
void FlowBuffer::set_eof() void FlowBuffer::set_eof() {
{ // fprintf(stderr, "EOF\n");
// fprintf(stderr, "EOF\n"); eof_ = true;
eof_ = true; if ( chunked_ )
if ( chunked_ ) frame_length_ = orig_data_end_ - orig_data_begin_;
frame_length_ = orig_data_end_ - orig_data_begin_; if ( frame_length_ < 0 )
if ( frame_length_ < 0 ) frame_length_ = 0;
frame_length_ = 0; }
}
void FlowBuffer::NewData(const_byteptr begin, const_byteptr end) void FlowBuffer::NewData(const_byteptr begin, const_byteptr end) {
{ BINPAC_ASSERT(begin <= end);
BINPAC_ASSERT(begin <= end);
ClearPreviousData(); ClearPreviousData();
BINPAC_ASSERT((buffer_n_ == 0 && message_complete_) || orig_data_begin_ == orig_data_end_); BINPAC_ASSERT((buffer_n_ == 0 && message_complete_) || orig_data_begin_ == orig_data_end_);
orig_data_begin_ = begin; orig_data_begin_ = begin;
orig_data_end_ = end; orig_data_end_ = end;
data_seq_at_orig_data_end_ += (end - begin); data_seq_at_orig_data_end_ += (end - begin);
MarkOrCopy(); MarkOrCopy();
} }
void FlowBuffer::MarkOrCopy() void FlowBuffer::MarkOrCopy() {
{ if ( ! message_complete_ ) {
if ( ! message_complete_ ) switch ( mode_ ) {
{ case LINE_MODE: MarkOrCopyLine(); break;
switch ( mode_ )
{
case LINE_MODE:
MarkOrCopyLine();
break;
case FRAME_MODE: case FRAME_MODE: MarkOrCopyFrame(); break;
MarkOrCopyFrame();
break;
default: default: break;
break; }
} }
} }
}
void FlowBuffer::ClearPreviousData() void FlowBuffer::ClearPreviousData() {
{ // All previous data must have been processed or buffered already
// All previous data must have been processed or buffered already if ( orig_data_begin_ < orig_data_end_ ) {
if ( orig_data_begin_ < orig_data_end_ ) BINPAC_ASSERT(buffer_n_ == 0);
{ if ( chunked_ ) {
BINPAC_ASSERT(buffer_n_ == 0); if ( frame_length_ > 0 ) {
if ( chunked_ ) frame_length_ -= (orig_data_end_ - orig_data_begin_);
{ }
if ( frame_length_ > 0 ) orig_data_begin_ = orig_data_end_;
{ }
frame_length_ -= (orig_data_end_ - orig_data_begin_); }
} }
orig_data_begin_ = orig_data_end_;
}
}
}
void FlowBuffer::NewGap(int length) void FlowBuffer::NewGap(int length) {
{ ClearPreviousData();
ClearPreviousData();
if ( chunked_ && frame_length_ >= 0 ) if ( chunked_ && frame_length_ >= 0 ) {
{ frame_length_ -= length;
frame_length_ -= length; if ( frame_length_ < 0 )
if ( frame_length_ < 0 ) frame_length_ = 0;
frame_length_ = 0; }
}
orig_data_begin_ = orig_data_end_ = nullptr; orig_data_begin_ = orig_data_end_ = nullptr;
MarkOrCopy(); MarkOrCopy();
} }
void FlowBuffer::MarkOrCopyLine() void FlowBuffer::MarkOrCopyLine() {
{ switch ( linebreak_style_ ) {
switch ( linebreak_style_ ) case CR_OR_LF: MarkOrCopyLine_CR_OR_LF(); break;
{ case STRICT_CRLF: MarkOrCopyLine_STRICT_CRLF(); break;
case CR_OR_LF: case LINE_BREAKER: MarkOrCopyLine_LINEBREAK(); break;
MarkOrCopyLine_CR_OR_LF(); default: BINPAC_ASSERT(0); break;
break; }
case STRICT_CRLF: }
MarkOrCopyLine_STRICT_CRLF();
break;
case LINE_BREAKER:
MarkOrCopyLine_LINEBREAK();
break;
default:
BINPAC_ASSERT(0);
break;
}
}
/* /*
Finite state automaton for CR_OR_LF: Finite state automaton for CR_OR_LF:
@ -327,57 +265,49 @@ CR_OR_LF_1:
.: CR_OR_LF_0 * .: CR_OR_LF_0 *
*/ */
void FlowBuffer::MarkOrCopyLine_CR_OR_LF() void FlowBuffer::MarkOrCopyLine_CR_OR_LF() {
{ if ( ! (orig_data_begin_ && orig_data_end_) )
if ( ! (orig_data_begin_ && orig_data_end_) ) return;
return;
if ( state_ == CR_OR_LF_1 && orig_data_begin_ < orig_data_end_ && *orig_data_begin_ == LF ) if ( state_ == CR_OR_LF_1 && orig_data_begin_ < orig_data_end_ && *orig_data_begin_ == LF ) {
{ state_ = CR_OR_LF_0;
state_ = CR_OR_LF_0; ++orig_data_begin_;
++orig_data_begin_; }
}
const_byteptr data; const_byteptr data;
for ( data = orig_data_begin_; data < orig_data_end_; ++data ) for ( data = orig_data_begin_; data < orig_data_end_; ++data ) {
{ switch ( *data ) {
switch ( *data ) case CR: state_ = CR_OR_LF_1; goto found_end_of_line;
{
case CR:
state_ = CR_OR_LF_1;
goto found_end_of_line;
case LF: case LF:
// state_ = CR_OR_LF_0; // state_ = CR_OR_LF_0;
goto found_end_of_line; goto found_end_of_line;
default: default:
// state_ = CR_OR_LF_0; // state_ = CR_OR_LF_0;
break; break;
} }
} }
AppendToBuffer(orig_data_begin_, orig_data_end_ - orig_data_begin_); AppendToBuffer(orig_data_begin_, orig_data_end_ - orig_data_begin_);
return; return;
found_end_of_line: found_end_of_line:
if ( buffer_n_ == 0 ) if ( buffer_n_ == 0 ) {
{ frame_length_ = data - orig_data_begin_;
frame_length_ = data - orig_data_begin_; }
} else {
else AppendToBuffer(orig_data_begin_, data + 1 - orig_data_begin_);
{ // But eliminate the last CR or LF
AppendToBuffer(orig_data_begin_, data + 1 - orig_data_begin_); --buffer_n_;
// But eliminate the last CR or LF }
--buffer_n_; message_complete_ = true;
}
message_complete_ = true;
#if DEBUG_FLOW_BUFFER #if DEBUG_FLOW_BUFFER
fprintf(stderr, "%.6f Line complete: [%s]\n", network_time(), fprintf(stderr, "%.6f Line complete: [%s]\n", network_time(),
string((const char*)begin(), (const char*)end()).c_str()); string((const char*)begin(), (const char*)end()).c_str());
#endif #endif
} }
/* /*
Finite state automaton and STRICT_CRLF: Finite state automaton and STRICT_CRLF:
@ -394,87 +324,73 @@ STRICT_CRLF_1:
.: STRICT_CRLF_0 * .: STRICT_CRLF_0 *
*/ */
void FlowBuffer::MarkOrCopyLine_STRICT_CRLF() void FlowBuffer::MarkOrCopyLine_STRICT_CRLF() {
{ const_byteptr data;
const_byteptr data; for ( data = orig_data_begin_; data < orig_data_end_; ++data ) {
for ( data = orig_data_begin_; data < orig_data_end_; ++data ) switch ( *data ) {
{ case CR: state_ = STRICT_CRLF_1; break;
switch ( *data )
{
case CR:
state_ = STRICT_CRLF_1;
break;
case LF: case LF:
if ( state_ == STRICT_CRLF_1 ) if ( state_ == STRICT_CRLF_1 ) {
{ state_ = STRICT_CRLF_0;
state_ = STRICT_CRLF_0; goto found_end_of_line;
goto found_end_of_line; }
} break;
break;
default: default: state_ = STRICT_CRLF_0; break;
state_ = STRICT_CRLF_0; }
break; }
}
}
AppendToBuffer(orig_data_begin_, orig_data_end_ - orig_data_begin_); AppendToBuffer(orig_data_begin_, orig_data_end_ - orig_data_begin_);
return; return;
found_end_of_line: found_end_of_line:
if ( buffer_n_ == 0 ) if ( buffer_n_ == 0 ) {
{ frame_length_ = data - 1 - orig_data_begin_;
frame_length_ = data - 1 - orig_data_begin_; }
} else {
else AppendToBuffer(orig_data_begin_, data + 1 - orig_data_begin_);
{ // Pop the preceding CR and LF from the buffer
AppendToBuffer(orig_data_begin_, data + 1 - orig_data_begin_); buffer_n_ -= 2;
// Pop the preceding CR and LF from the buffer }
buffer_n_ -= 2;
}
message_complete_ = true; message_complete_ = true;
#if DEBUG_FLOW_BUFFER #if DEBUG_FLOW_BUFFER
fprintf(stderr, "%.6f Line complete: [%s]\n", network_time(), fprintf(stderr, "%.6f Line complete: [%s]\n", network_time(),
string((const char*)begin(), (const char*)end()).c_str()); string((const char*)begin(), (const char*)end()).c_str());
#endif #endif
} }
void FlowBuffer::MarkOrCopyLine_LINEBREAK() void FlowBuffer::MarkOrCopyLine_LINEBREAK() {
{ if ( ! (orig_data_begin_ && orig_data_end_) )
if ( ! (orig_data_begin_ && orig_data_end_) ) return;
return;
const_byteptr data; const_byteptr data;
for ( data = orig_data_begin_; data < orig_data_end_; ++data ) for ( data = orig_data_begin_; data < orig_data_end_; ++data ) {
{ if ( *data == linebreaker_ )
if ( *data == linebreaker_ ) goto found_end_of_line;
goto found_end_of_line; }
}
AppendToBuffer(orig_data_begin_, orig_data_end_ - orig_data_begin_); AppendToBuffer(orig_data_begin_, orig_data_end_ - orig_data_begin_);
return; return;
found_end_of_line: found_end_of_line:
if ( buffer_n_ == 0 ) if ( buffer_n_ == 0 ) {
{ frame_length_ = data - orig_data_begin_;
frame_length_ = data - orig_data_begin_; }
} else {
else AppendToBuffer(orig_data_begin_, data + 1 - orig_data_begin_);
{ // But eliminate the last 'linebreaker' character
AppendToBuffer(orig_data_begin_, data + 1 - orig_data_begin_); --buffer_n_;
// But eliminate the last CR or LF }
--buffer_n_; message_complete_ = true;
}
message_complete_ = true;
#if DEBUG_FLOW_BUFFER #if DEBUG_FLOW_BUFFER
fprintf(stderr, "%.6f Line complete: [%s]\n", network_time(), fprintf(stderr, "%.6f Line complete: [%s]\n", network_time(),
string((const char*)begin(), (const char*)end()).c_str()); string((const char*)begin(), (const char*)end()).c_str());
#endif #endif
} }
// Invariants: // Invariants:
// //
@ -484,69 +400,58 @@ found_end_of_line:
// When buffer_n_ > 0: // When buffer_n_ > 0:
// Frame = [0..buffer_n_][orig_data_begin_..] // Frame = [0..buffer_n_][orig_data_begin_..]
void FlowBuffer::MarkOrCopyFrame() void FlowBuffer::MarkOrCopyFrame() {
{ if ( mode_ == FRAME_MODE && state_ == CR_OR_LF_1 && orig_data_begin_ < orig_data_end_ ) {
if ( mode_ == FRAME_MODE && state_ == CR_OR_LF_1 && orig_data_begin_ < orig_data_end_ ) // Skip the lingering LF
{ if ( *orig_data_begin_ == LF ) {
// Skip the lingering LF ++orig_data_begin_;
if ( *orig_data_begin_ == LF ) }
{ state_ = FRAME_0;
++orig_data_begin_; }
}
state_ = FRAME_0;
}
if ( buffer_n_ == 0 ) if ( buffer_n_ == 0 ) {
{ // If there is enough data
// If there is enough data if ( frame_length_ >= 0 && orig_data_end_ - orig_data_begin_ >= frame_length_ ) {
if ( frame_length_ >= 0 && orig_data_end_ - orig_data_begin_ >= frame_length_ ) // Do nothing except setting the message complete flag
{ message_complete_ = true;
// Do nothing except setting the message complete flag }
message_complete_ = true; else {
} if ( ! chunked_ ) {
else AppendToBuffer(orig_data_begin_, orig_data_end_ - orig_data_begin_);
{ }
if ( ! chunked_ ) message_complete_ = false;
{ }
AppendToBuffer(orig_data_begin_, orig_data_end_ - orig_data_begin_); }
} else {
message_complete_ = false; BINPAC_ASSERT(! chunked_);
} int bytes_to_copy = orig_data_end_ - orig_data_begin_;
} message_complete_ = false;
else if ( frame_length_ >= 0 && buffer_n_ + bytes_to_copy >= frame_length_ ) {
{ bytes_to_copy = frame_length_ - buffer_n_;
BINPAC_ASSERT(! chunked_); message_complete_ = true;
int bytes_to_copy = orig_data_end_ - orig_data_begin_; }
message_complete_ = false; AppendToBuffer(orig_data_begin_, bytes_to_copy);
if ( frame_length_ >= 0 && buffer_n_ + bytes_to_copy >= frame_length_ ) }
{
bytes_to_copy = frame_length_ - buffer_n_;
message_complete_ = true;
}
AppendToBuffer(orig_data_begin_, bytes_to_copy);
}
#if DEBUG_FLOW_BUFFER #if DEBUG_FLOW_BUFFER
if ( message_complete_ ) if ( message_complete_ ) {
{ fprintf(stderr, "%.6f frame complete: [%s]\n", network_time(),
fprintf(stderr, "%.6f frame complete: [%s]\n", network_time(), string((const char*)begin(), (const char*)end()).c_str());
string((const char*)begin(), (const char*)end()).c_str()); }
}
#endif #endif
} }
void FlowBuffer::AppendToBuffer(const_byteptr data, int len) void FlowBuffer::AppendToBuffer(const_byteptr data, int len) {
{ if ( len <= 0 )
if ( len <= 0 ) return;
return;
BINPAC_ASSERT(! chunked_); BINPAC_ASSERT(! chunked_);
ExpandBuffer(buffer_n_ + len); ExpandBuffer(buffer_n_ + len);
memcpy(buffer_ + buffer_n_, data, len); memcpy(buffer_ + buffer_n_, data, len);
buffer_n_ += len; buffer_n_ += len;
orig_data_begin_ += len; orig_data_begin_ += len;
BINPAC_ASSERT(orig_data_begin_ <= orig_data_end_); BINPAC_ASSERT(orig_data_begin_ <= orig_data_end_);
} }
} // namespace binpac } // namespace binpac

View file

@ -5,179 +5,164 @@
#include "binpac.h" #include "binpac.h"
namespace binpac namespace binpac {
{
class FlowBuffer class FlowBuffer {
{
public: public:
struct Policy struct Policy {
{ int max_capacity;
int max_capacity; int min_capacity;
int min_capacity; int contract_threshold;
int contract_threshold; };
};
enum LineBreakStyle enum LineBreakStyle {
{ CR_OR_LF, // CR or LF or CRLF
CR_OR_LF, // CR or LF or CRLF STRICT_CRLF, // CR followed by LF
STRICT_CRLF, // CR followed by LF CR_LF_NUL, // CR or LF or CR-LF or CR-NUL
CR_LF_NUL, // CR or LF or CR-LF or CR-NUL LINE_BREAKER, // User specified linebreaker
LINE_BREAKER, // User specified linebreaker };
};
FlowBuffer(LineBreakStyle linebreak_style = CR_OR_LF); FlowBuffer(LineBreakStyle linebreak_style = CR_OR_LF);
virtual ~FlowBuffer(); virtual ~FlowBuffer();
void NewData(const_byteptr begin, const_byteptr end); void NewData(const_byteptr begin, const_byteptr end);
void NewGap(int length); void NewGap(int length);
// Interface for delayed parsing. Sometimes BinPAC doesn't get the // Interface for delayed parsing. Sometimes BinPAC doesn't get the
// buffering right and then one can use these to feed parts // buffering right and then one can use these to feed parts
// individually and assemble them internally. After calling // individually and assemble them internally. After calling
// FinishBuffer(), one can send the uppper-layer flow an FlowEOF() to // FinishBuffer(), one can send the uppper-layer flow an FlowEOF() to
// trigger parsing. // trigger parsing.
void BufferData(const_byteptr data, const_byteptr end); void BufferData(const_byteptr data, const_byteptr end);
void FinishBuffer(); void FinishBuffer();
// Discard unprocessed data // Discard unprocessed data
void DiscardData(); void DiscardData();
// Whether there is enough data for the frame // Whether there is enough data for the frame
bool ready() const { return message_complete_ || mode_ == UNKNOWN_MODE; } bool ready() const { return message_complete_ || mode_ == UNKNOWN_MODE; }
inline const_byteptr begin() const inline const_byteptr begin() const {
{ BINPAC_ASSERT(ready());
BINPAC_ASSERT(ready()); return (buffer_n_ == 0) ? orig_data_begin_ : buffer_;
return (buffer_n_ == 0) ? orig_data_begin_ : buffer_; }
}
inline const_byteptr end() const inline const_byteptr end() const {
{ BINPAC_ASSERT(ready());
BINPAC_ASSERT(ready()); if ( buffer_n_ == 0 ) {
if ( buffer_n_ == 0 ) BINPAC_ASSERT(frame_length_ >= 0);
{ const_byteptr end = orig_data_begin_ + frame_length_;
BINPAC_ASSERT(frame_length_ >= 0); BINPAC_ASSERT(end <= orig_data_end_);
const_byteptr end = orig_data_begin_ + frame_length_; return end;
BINPAC_ASSERT(end <= orig_data_end_); }
return end; else
} return buffer_ + buffer_n_;
else }
return buffer_ + buffer_n_;
}
inline int data_length() const inline int data_length() const {
{ if ( buffer_n_ > 0 )
if ( buffer_n_ > 0 ) return buffer_n_;
return buffer_n_;
if ( frame_length_ < 0 || orig_data_begin_ + frame_length_ > orig_data_end_ ) if ( frame_length_ < 0 || orig_data_begin_ + frame_length_ > orig_data_end_ )
return orig_data_end_ - orig_data_begin_; return orig_data_end_ - orig_data_begin_;
else else
return frame_length_; return frame_length_;
} }
inline bool data_available() const inline bool data_available() const { return buffer_n_ > 0 || orig_data_end_ > orig_data_begin_; }
{
return buffer_n_ > 0 || orig_data_end_ > orig_data_begin_;
}
void SetLineBreaker(unsigned char* lbreaker); void SetLineBreaker(unsigned char* lbreaker);
void UnsetLineBreaker(); void UnsetLineBreaker();
void NewLine(); void NewLine();
// A negative frame_length represents a frame till EOF // A negative frame_length represents a frame till EOF
void NewFrame(int frame_length, bool chunked_); void NewFrame(int frame_length, bool chunked_);
void GrowFrame(int new_frame_length); void GrowFrame(int new_frame_length);
int data_seq() const int data_seq() const {
{ int data_seq_at_orig_data_begin = data_seq_at_orig_data_end_ - (orig_data_end_ - orig_data_begin_);
int data_seq_at_orig_data_begin = data_seq_at_orig_data_end_ - if ( buffer_n_ > 0 )
(orig_data_end_ - orig_data_begin_); return data_seq_at_orig_data_begin;
if ( buffer_n_ > 0 ) else
return data_seq_at_orig_data_begin; return data_seq_at_orig_data_begin + data_length();
else }
return data_seq_at_orig_data_begin + data_length(); bool eof() const { return eof_; }
} void set_eof();
bool eof() const { return eof_; }
void set_eof();
bool have_pending_request() const { return have_pending_request_; } bool have_pending_request() const { return have_pending_request_; }
static void init(Policy p) { policy = p; } static void init(Policy p) { policy = p; }
protected: protected:
// Reset the buffer for a new message // Reset the buffer for a new message
void NewMessage(); void NewMessage();
void ClearPreviousData(); void ClearPreviousData();
// Expand the buffer to at least <length> bytes. If there // Expand the buffer to at least <length> bytes. If there
// are contents in the existing buffer, copy them to the new // are contents in the existing buffer, copy them to the new
// buffer. // buffer.
void ExpandBuffer(int length); void ExpandBuffer(int length);
// Contract the buffer to some minimum capacity. // Contract the buffer to some minimum capacity.
// Existing contents in the buffer are preserved (but only usage // Existing contents in the buffer are preserved (but only usage
// at the time of creation this function is when the contents // at the time of creation this function is when the contents
// are being discarded due to parsing exception or have already been // are being discarded due to parsing exception or have already been
// copied out after parsing a complete unit). // copied out after parsing a complete unit).
void ContractBuffer(); void ContractBuffer();
// Reset line state when transit from frame mode to line mode. // Reset line state when transit from frame mode to line mode.
void ResetLineState(); void ResetLineState();
void AppendToBuffer(const_byteptr data, int len); void AppendToBuffer(const_byteptr data, int len);
// MarkOrCopy{Line,Frame} sets message_complete_ and // MarkOrCopy{Line,Frame} sets message_complete_ and
// marks begin/end pointers if a line/frame is complete, // marks begin/end pointers if a line/frame is complete,
// otherwise it clears message_complete_ and copies all // otherwise it clears message_complete_ and copies all
// the original data to the buffer. // the original data to the buffer.
// //
void MarkOrCopy(); void MarkOrCopy();
void MarkOrCopyLine(); void MarkOrCopyLine();
void MarkOrCopyFrame(); void MarkOrCopyFrame();
void MarkOrCopyLine_CR_OR_LF(); void MarkOrCopyLine_CR_OR_LF();
void MarkOrCopyLine_STRICT_CRLF(); void MarkOrCopyLine_STRICT_CRLF();
void MarkOrCopyLine_LINEBREAK(); void MarkOrCopyLine_LINEBREAK();
int buffer_n_; // number of bytes in the buffer int buffer_n_; // number of bytes in the buffer
int buffer_length_; // size of the buffer int buffer_length_; // size of the buffer
unsigned char* buffer_; unsigned char* buffer_;
bool message_complete_; bool message_complete_;
int frame_length_; int frame_length_;
bool chunked_; bool chunked_;
const_byteptr orig_data_begin_, orig_data_end_; const_byteptr orig_data_begin_, orig_data_end_;
LineBreakStyle linebreak_style_; LineBreakStyle linebreak_style_;
LineBreakStyle linebreak_style_default; LineBreakStyle linebreak_style_default;
unsigned char linebreaker_; unsigned char linebreaker_;
enum enum {
{ UNKNOWN_MODE,
UNKNOWN_MODE, LINE_MODE,
LINE_MODE, FRAME_MODE,
FRAME_MODE, } mode_;
} mode_;
enum enum {
{ CR_OR_LF_0,
CR_OR_LF_0, CR_OR_LF_1,
CR_OR_LF_1, STRICT_CRLF_0,
STRICT_CRLF_0, STRICT_CRLF_1,
STRICT_CRLF_1, FRAME_0,
FRAME_0, } state_;
} state_;
int data_seq_at_orig_data_end_; int data_seq_at_orig_data_end_;
bool eof_; bool eof_;
bool have_pending_request_; bool have_pending_request_;
static Policy policy; static Policy policy;
}; };
typedef FlowBuffer* flow_buffer_t; typedef FlowBuffer* flow_buffer_t;
} // namespace binpac } // namespace binpac
#endif // binpac_buffer_h #endif // binpac_buffer_h

View file

@ -4,22 +4,12 @@
#include <stdlib.h> #include <stdlib.h>
namespace binpac namespace binpac {
{
std::string std_string(bytestring const* s) std::string std_string(bytestring const* s) { return std::string((const char*)s->begin(), (const char*)s->end()); }
{
return std::string((const char*)s->begin(), (const char*)s->end());
}
int bytestring_to_int(bytestring const* s) int bytestring_to_int(bytestring const* s) { return atoi((const char*)s->begin()); }
{
return atoi((const char*)s->begin());
}
double bytestring_to_double(bytestring const* s) double bytestring_to_double(bytestring const* s) { return atof((const char*)s->begin()); }
{
return atof((const char*)s->begin());
}
} // namespace binpac } // namespace binpac

View file

@ -6,155 +6,137 @@
#include "binpac.h" #include "binpac.h"
namespace binpac namespace binpac {
{
template <class T> class datastring; template<class T>
class datastring;
template <class T> class const_datastring template<class T>
{ class const_datastring {
public: public:
const_datastring() : begin_(0), end_(0) { } const_datastring() : begin_(0), end_(0) {}
const_datastring(T const* data, int length) : begin_(data), end_(data + length) { } const_datastring(T const* data, int length) : begin_(data), end_(data + length) {}
const_datastring(const T* begin, const T* end) : begin_(begin), end_(end) { } const_datastring(const T* begin, const T* end) : begin_(begin), end_(end) {}
const_datastring(datastring<T> const& s) : begin_(s.begin()), end_(s.end()) { } const_datastring(datastring<T> const& s) : begin_(s.begin()), end_(s.end()) {}
void init(const T* data, int length) void init(const T* data, int length) {
{ begin_ = data;
begin_ = data; end_ = data + length;
end_ = data + length; }
}
T const* begin() const { return begin_; } T const* begin() const { return begin_; }
T const* end() const { return end_; } T const* end() const { return end_; }
int length() const { return end_ - begin_; } int length() const { return end_ - begin_; }
T const& operator[](int index) const { return begin()[index]; } T const& operator[](int index) const { return begin()[index]; }
bool operator==(const_datastring<T> const& s) bool operator==(const_datastring<T> const& s) {
{ if ( length() != s.length() )
if ( length() != s.length() ) return false;
return false; return memcmp((const void*)begin(), (const void*)s.begin(), sizeof(T) * length()) == 0;
return memcmp((const void*)begin(), (const void*)s.begin(), sizeof(T) * length()) == 0; }
}
void set_begin(T const* begin) { begin_ = begin; } void set_begin(T const* begin) { begin_ = begin; }
void set_end(T const* end) { end_ = end; } void set_end(T const* end) { end_ = end; }
private: private:
T const* begin_; T const* begin_;
T const* end_; T const* end_;
}; };
typedef const_datastring<uint8> const_bytestring; typedef const_datastring<uint8> const_bytestring;
template <class T> class datastring template<class T>
{ class datastring {
public: public:
datastring() { clear(); } datastring() { clear(); }
datastring(T* data, int len) { set(data, len); } datastring(T* data, int len) { set(data, len); }
datastring(T const* begin, T const* end) { set_const(begin, end - begin); } datastring(T const* begin, T const* end) { set_const(begin, end - begin); }
datastring(datastring<T> const& x) : data_(x.data()), length_(x.length()) { } datastring(datastring<T> const& x) : data_(x.data()), length_(x.length()) {}
explicit datastring(const_datastring<T> const& x) { set_const(x.begin(), x.length()); } explicit datastring(const_datastring<T> const& x) { set_const(x.begin(), x.length()); }
datastring const& operator=(datastring<T> const& x) datastring const& operator=(datastring<T> const& x) {
{ BINPAC_ASSERT(! data_);
BINPAC_ASSERT(! data_); set(x.data(), x.length());
set(x.data(), x.length()); return *this;
return *this; }
}
void init(T const* begin, int length) void init(T const* begin, int length) {
{ BINPAC_ASSERT(! data_);
BINPAC_ASSERT(! data_); set_const(begin, length);
set_const(begin, length); }
}
void clear() void clear() {
{ data_ = 0;
data_ = 0; length_ = 0;
length_ = 0; }
}
void free() void free() {
{ if ( data_ )
if ( data_ ) delete[] data_;
delete[] data_; clear();
clear(); }
}
void clone() { set_const(begin(), length()); } void clone() { set_const(begin(), length()); }
datastring const& operator=(const_datastring<T> const& x) datastring const& operator=(const_datastring<T> const& x) {
{ BINPAC_ASSERT(! data_);
BINPAC_ASSERT(! data_); set_const(x.begin(), x.length());
set_const(x.begin(), x.length()); return *this;
return *this; }
}
T const& operator[](int index) const { return begin()[index]; } T const& operator[](int index) const { return begin()[index]; }
T* data() const { return data_; } T* data() const { return data_; }
int length() const { return length_; } int length() const { return length_; }
T const* begin() const { return data_; } T const* begin() const { return data_; }
T const* end() const { return data_ + length_; } T const* end() const { return data_ + length_; }
private: private:
void set(T* data, int len) void set(T* data, int len) {
{ data_ = data;
data_ = data; length_ = len;
length_ = len; }
}
void set_const(T const* data, int len) void set_const(T const* data, int len) {
{ length_ = len;
length_ = len; data_ = new T[len + 1];
data_ = new T[len + 1]; memcpy(data_, data, sizeof(T) * len);
memcpy(data_, data, sizeof(T) * len); data_[len] = 0;
data_[len] = 0; }
}
T* data_; T* data_;
int length_; int length_;
}; };
typedef datastring<uint8> bytestring; typedef datastring<uint8> bytestring;
inline const char* c_str(bytestring const& s) inline const char* c_str(bytestring const& s) { return (const char*)s.begin(); }
{
return (const char*)s.begin();
}
inline std::string std_str(const_bytestring const& s) inline std::string std_str(const_bytestring const& s) {
{ return std::string((const char*)s.begin(), (const char*)s.end());
return std::string((const char*)s.begin(), (const char*)s.end()); }
}
inline bool operator==(bytestring const& s1, const char* s2) inline bool operator==(bytestring const& s1, const char* s2) { return strcmp(c_str(s1), s2) == 0; }
{
return strcmp(c_str(s1), s2) == 0;
}
inline void get_pointers(const_bytestring const& s, uint8 const** pbegin, uint8 const** pend) inline void get_pointers(const_bytestring const& s, uint8 const** pbegin, uint8 const** pend) {
{ *pbegin = s.begin();
*pbegin = s.begin(); *pend = s.end();
*pend = s.end(); }
}
inline void get_pointers(bytestring const* s, uint8 const** pbegin, uint8 const** pend) inline void get_pointers(bytestring const* s, uint8 const** pbegin, uint8 const** pend) {
{ *pbegin = s->begin();
*pbegin = s->begin(); *pend = s->end();
*pend = s->end(); }
}
} // namespace binpac } // namespace binpac
#endif // binpac_bytestring_h #endif // binpac_bytestring_h

View file

@ -4,117 +4,92 @@
#include <inttypes.h> #include <inttypes.h>
#include <stdint.h> #include <stdint.h>
namespace binpac namespace binpac {
{
class Exception class Exception {
{
public: public:
Exception(const char* m = 0) : msg_("binpac exception: ") Exception(const char* m = 0) : msg_("binpac exception: ") {
{ if ( m )
if ( m ) append(m);
append(m); // abort();
// abort(); }
}
void append(string m) { msg_ += m; } void append(string m) { msg_ += m; }
string msg() const { return msg_; } string msg() const { return msg_; }
const char* c_msg() const { return msg_.c_str(); } const char* c_msg() const { return msg_.c_str(); }
protected: protected:
string msg_; string msg_;
}; };
class ExceptionEnforceViolation : public Exception class ExceptionEnforceViolation : public Exception {
{
public: public:
ExceptionEnforceViolation(const char* where) ExceptionEnforceViolation(const char* where) { append(binpac_fmt("&enforce violation : %s", where)); }
{ };
append(binpac_fmt("&enforce violation : %s", where));
}
};
class ExceptionOutOfBound : public Exception class ExceptionOutOfBound : public Exception {
{
public: public:
ExceptionOutOfBound(const char* where, int len_needed, int len_given) ExceptionOutOfBound(const char* where, int len_needed, int len_given) {
{ append(binpac_fmt("out_of_bound: %s: %d > %d", where, len_needed, len_given));
append(binpac_fmt("out_of_bound: %s: %d > %d", where, len_needed, len_given)); }
} };
};
class ExceptionInvalidCase : public Exception class ExceptionInvalidCase : public Exception {
{
public: public:
ExceptionInvalidCase(const char* location, int64_t index, const char* expected) ExceptionInvalidCase(const char* location, int64_t index, const char* expected)
: location_(location), index_(index), expected_(expected) : location_(location), index_(index), expected_(expected) {
{ append(binpac_fmt("invalid case: %s: %" PRIi64 " (%s)", location, index, expected));
append(binpac_fmt("invalid case: %s: %" PRIi64 " (%s)", location, index, expected)); }
}
protected: protected:
const char* location_; const char* location_;
int64_t index_; int64_t index_;
string expected_; string expected_;
}; };
class ExceptionInvalidCaseIndex : public Exception class ExceptionInvalidCaseIndex : public Exception {
{
public: public:
ExceptionInvalidCaseIndex(const char* location, int64_t index) ExceptionInvalidCaseIndex(const char* location, int64_t index) : location_(location), index_(index) {
: location_(location), index_(index) append(binpac_fmt("invalid index for case: %s: %" PRIi64, location, index));
{ }
append(binpac_fmt("invalid index for case: %s: %" PRIi64, location, index));
}
protected: protected:
const char* location_; const char* location_;
int64_t index_; int64_t index_;
}; };
class ExceptionInvalidOffset : public Exception class ExceptionInvalidOffset : public Exception {
{
public: public:
ExceptionInvalidOffset(const char* location, int min_offset, int offset) ExceptionInvalidOffset(const char* location, int min_offset, int offset)
: location_(location), min_offset_(min_offset), offset_(offset) : location_(location), min_offset_(min_offset), offset_(offset) {
{ append(binpac_fmt("invalid offset: %s: min_offset = %d, offset = %d", location, min_offset, offset));
append(binpac_fmt("invalid offset: %s: min_offset = %d, offset = %d", location, min_offset, }
offset));
}
protected: protected:
const char* location_; const char* location_;
int min_offset_, offset_; int min_offset_, offset_;
}; };
class ExceptionStringMismatch : public Exception class ExceptionStringMismatch : public Exception {
{
public: public:
ExceptionStringMismatch(const char* location, const char* expected, const char* actual_data) ExceptionStringMismatch(const char* location, const char* expected, const char* actual_data) {
{ append(binpac_fmt("string mismatch at %s: \nexpected pattern: \"%s\"\nactual data: \"%s\"", location, expected,
append(binpac_fmt("string mismatch at %s: \nexpected pattern: \"%s\"\nactual data: \"%s\"", actual_data));
location, expected, actual_data)); }
} };
};
class ExceptionInvalidStringLength : public Exception class ExceptionInvalidStringLength : public Exception {
{
public: public:
ExceptionInvalidStringLength(const char* location, int len) ExceptionInvalidStringLength(const char* location, int len) {
{ append(binpac_fmt("invalid length string: %s: %d", location, len));
append(binpac_fmt("invalid length string: %s: %d", location, len)); }
} };
};
class ExceptionFlowBufferAlloc : public Exception class ExceptionFlowBufferAlloc : public Exception {
{
public: public:
ExceptionFlowBufferAlloc(const char* reason) ExceptionFlowBufferAlloc(const char* reason) { append(binpac_fmt("flowbuffer allocation failed: %s", reason)); }
{ };
append(binpac_fmt("flowbuffer allocation failed: %s", reason));
}
};
} } // namespace binpac
#endif // binpac_exception_h #endif // binpac_exception_h

View file

@ -1,11 +1,12 @@
#include <vector> #include <vector>
namespace zeek { class RE_Matcher; } namespace zeek {
class RE_Matcher;
}
namespace binpac namespace binpac {
{
std::vector<zeek::RE_Matcher*>* uncompiled_re_matchers = nullptr; std::vector<zeek::RE_Matcher*>* uncompiled_re_matchers = nullptr;
} }

View file

@ -5,13 +5,11 @@
#include "binpac.h" #include "binpac.h"
namespace zeek namespace zeek {
{
class RE_Matcher; class RE_Matcher;
} }
namespace binpac namespace binpac {
{
// Must be called before any binpac functionality is used. // Must be called before any binpac functionality is used.
// //
@ -23,58 +21,52 @@ inline void init(FlowBuffer::Policy* fbp = 0);
// Internal vector recording not yet compiled matchers. // Internal vector recording not yet compiled matchers.
extern std::vector<zeek::RE_Matcher*>* uncompiled_re_matchers; extern std::vector<zeek::RE_Matcher*>* uncompiled_re_matchers;
class RegExMatcher class RegExMatcher {
{
public: public:
RegExMatcher(const char* pattern) : pattern_(pattern) RegExMatcher(const char* pattern) : pattern_(pattern) {
{ if ( ! uncompiled_re_matchers )
if ( ! uncompiled_re_matchers ) uncompiled_re_matchers = new std::vector<zeek::RE_Matcher*>;
uncompiled_re_matchers = new std::vector<zeek::RE_Matcher*>;
re_matcher_ = new zeek::RE_Matcher(pattern_.c_str()); re_matcher_ = new zeek::RE_Matcher(pattern_.c_str());
uncompiled_re_matchers->push_back(re_matcher_); uncompiled_re_matchers->push_back(re_matcher_);
} }
~RegExMatcher() { delete re_matcher_; } ~RegExMatcher() { delete re_matcher_; }
// Returns the length of longest match, or -1 on mismatch. // Returns the length of longest match, or -1 on mismatch.
int MatchPrefix(const_byteptr data, int len) { return re_matcher_->MatchPrefix(data, len); } int MatchPrefix(const_byteptr data, int len) { return re_matcher_->MatchPrefix(data, len); }
private: private:
friend void ::binpac::init(FlowBuffer::Policy*); friend void ::binpac::init(FlowBuffer::Policy*);
// Function, and state, for compiling matchers. // Function, and state, for compiling matchers.
static void init(); static void init();
string pattern_; string pattern_;
zeek::RE_Matcher* re_matcher_; zeek::RE_Matcher* re_matcher_;
}; };
inline void RegExMatcher::init() inline void RegExMatcher::init() {
{ if ( ! uncompiled_re_matchers )
if ( ! uncompiled_re_matchers ) return;
return;
for ( size_t i = 0; i < uncompiled_re_matchers->size(); ++i ) for ( size_t i = 0; i < uncompiled_re_matchers->size(); ++i ) {
{ if ( ! (*uncompiled_re_matchers)[i]->Compile() ) {
if ( ! (*uncompiled_re_matchers)[i]->Compile() ) fprintf(stderr, "binpac: cannot compile regular expression\n");
{ exit(1);
fprintf(stderr, "binpac: cannot compile regular expression\n"); }
exit(1); }
}
}
uncompiled_re_matchers->clear(); uncompiled_re_matchers->clear();
} }
inline void init(FlowBuffer::Policy* fbp) inline void init(FlowBuffer::Policy* fbp) {
{ RegExMatcher::init();
RegExMatcher::init();
if ( fbp ) if ( fbp )
FlowBuffer::init(*fbp); FlowBuffer::init(*fbp);
} }
} // namespace binpac } // namespace binpac
#endif // binpac_regex_h #endif // binpac_regex_h

View file

@ -9,93 +9,72 @@
#include "pac_utils.h" #include "pac_utils.h"
AnalyzerAction::AnalyzerAction(ID* action_id, When when, ActionParam* param, EmbeddedCode* code) AnalyzerAction::AnalyzerAction(ID* action_id, When when, ActionParam* param, EmbeddedCode* code)
: AnalyzerElement(ACTION), action_id_(action_id), when_(when), param_(param), code_(code), : AnalyzerElement(ACTION), action_id_(action_id), when_(when), param_(param), code_(code), analyzer_(nullptr) {}
analyzer_(nullptr)
{
}
AnalyzerAction::~AnalyzerAction() AnalyzerAction::~AnalyzerAction() {
{ delete action_id_;
delete action_id_; delete param_;
delete param_; delete code_;
delete code_; }
}
string AnalyzerAction::action_function() const string AnalyzerAction::action_function() const { return strfmt("Action_%s", action_id_->Name()); }
{
return strfmt("Action_%s", action_id_->Name());
}
void AnalyzerAction::InstallHook(AnalyzerDecl* analyzer) void AnalyzerAction::InstallHook(AnalyzerDecl* analyzer) {
{ ASSERT(0);
ASSERT(0); analyzer_ = analyzer;
analyzer_ = analyzer; // param_->MainDataType()->InstallAction(this);
// param_->MainDataType()->InstallAction(this); }
}
void AnalyzerAction::GenCode(Output* out_h, Output* out_cc, AnalyzerDecl* decl) void AnalyzerAction::GenCode(Output* out_h, Output* out_cc, AnalyzerDecl* decl) {
{ Env action_func_env(decl->env(), this);
Env action_func_env(decl->env(), this); action_func_env.AddID(param_->id(), TEMP_VAR, param_->DataType());
action_func_env.AddID(param_->id(), TEMP_VAR, param_->DataType()); action_func_env.SetEvaluated(param_->id());
action_func_env.SetEvaluated(param_->id());
string action_func_proto = strfmt("%s(%s)", action_function().c_str(), string action_func_proto = strfmt("%s(%s)", action_function().c_str(), ParamDecls(&action_func_env).c_str());
ParamDecls(&action_func_env).c_str());
out_h->println("void %s;", action_func_proto.c_str()); out_h->println("void %s;", action_func_proto.c_str());
out_cc->println("void %s::%s", decl->class_name().c_str(), action_func_proto.c_str()); out_cc->println("void %s::%s", decl->class_name().c_str(), action_func_proto.c_str());
out_cc->inc_indent(); out_cc->inc_indent();
out_cc->println("{"); out_cc->println("{");
code_->GenCode(out_cc, &action_func_env); code_->GenCode(out_cc, &action_func_env);
out_cc->println(""); out_cc->println("");
out_cc->println("}"); out_cc->println("}");
out_cc->dec_indent(); out_cc->dec_indent();
out_cc->println(""); out_cc->println("");
} }
string AnalyzerAction::ParamDecls(Env* env) const string AnalyzerAction::ParamDecls(Env* env) const { return param_->DeclStr(env); }
{
return param_->DeclStr(env);
}
Type* ActionParam::MainDataType() const Type* ActionParam::MainDataType() const {
{ // Note: this is not equal to DataType()
// Note: this is not equal to DataType() Type* main_type = TypeDecl::LookUpType(type()->type_id());
Type* main_type = TypeDecl::LookUpType(type()->type_id());
if ( ! main_type ) if ( ! main_type ) {
{ throw Exception(type()->type_id(), "type not defined");
throw Exception(type()->type_id(), "type not defined"); }
}
return main_type; return main_type;
} }
Type* ActionParam::DataType() const Type* ActionParam::DataType() const {
{ Type* main_type = MainDataType();
Type* main_type = MainDataType();
if ( ! type()->field_id() ) if ( ! type()->field_id() ) {
{ return main_type;
return main_type; }
} else {
else Type* member_type = main_type->MemberDataType(type()->field_id());
{ if ( ! member_type ) {
Type* member_type = main_type->MemberDataType(type()->field_id()); throw Exception(type()->field_id(), strfmt("cannot find member type for `%s.%s'", type()->type_id()->Name(),
if ( ! member_type ) type()->field_id()->Name()));
{ }
throw Exception(type()->field_id(), return member_type;
strfmt("cannot find member type for `%s.%s'", type()->type_id()->Name(), }
type()->field_id()->Name())); }
}
return member_type;
}
}
string ActionParam::DeclStr(Env* env) const string ActionParam::DeclStr(Env* env) const {
{ return strfmt("%s %s", DataType()->DataTypeStr().c_str(), env->LValue(id()));
return strfmt("%s %s", DataType()->DataTypeStr().c_str(), env->LValue(id())); }
}

View file

@ -6,71 +6,61 @@
#include "pac_analyzer.h" #include "pac_analyzer.h"
#include "pac_common.h" #include "pac_common.h"
class AnalyzerAction : public AnalyzerElement class AnalyzerAction : public AnalyzerElement {
{
public: public:
enum When enum When { BEFORE, AFTER };
{
BEFORE,
AFTER
};
AnalyzerAction(ID* action_id, When when, ActionParam* param, EmbeddedCode* code); AnalyzerAction(ID* action_id, When when, ActionParam* param, EmbeddedCode* code);
~AnalyzerAction() override; ~AnalyzerAction() override;
When when() const { return when_; } When when() const { return when_; }
ActionParam* param() const { return param_; } ActionParam* param() const { return param_; }
AnalyzerDecl* analyzer() const { return analyzer_; } AnalyzerDecl* analyzer() const { return analyzer_; }
string action_function() const; string action_function() const;
// Generate function prototype and code for the action // Generate function prototype and code for the action
void GenCode(Output* out_h, Output* out_cc, AnalyzerDecl* decl); void GenCode(Output* out_h, Output* out_cc, AnalyzerDecl* decl);
// Install the hook at the corresponding data type parsing // Install the hook at the corresponding data type parsing
// function to invoke the action. // function to invoke the action.
void InstallHook(AnalyzerDecl* analyzer); void InstallHook(AnalyzerDecl* analyzer);
private: private:
string ParamDecls(Env* env) const; string ParamDecls(Env* env) const;
ID* action_id_; ID* action_id_;
When when_; When when_;
ActionParam* param_; ActionParam* param_;
EmbeddedCode* code_; EmbeddedCode* code_;
AnalyzerDecl* analyzer_; AnalyzerDecl* analyzer_;
}; };
class ActionParam class ActionParam {
{
public: public:
ActionParam(const ID* id, ActionParamType* type) : id_(id), type_(type) { } ActionParam(const ID* id, ActionParamType* type) : id_(id), type_(type) {}
const ID* id() const { return id_; } const ID* id() const { return id_; }
ActionParamType* type() const { return type_; } ActionParamType* type() const { return type_; }
Type* MainDataType() const; Type* MainDataType() const;
Type* DataType() const; Type* DataType() const;
string DeclStr(Env* env) const; string DeclStr(Env* env) const;
private: private:
const ID* id_; const ID* id_;
ActionParamType* type_; ActionParamType* type_;
}; };
class ActionParamType class ActionParamType {
{
public: public:
ActionParamType(const ID* type_id, const ID* field_id = 0) ActionParamType(const ID* type_id, const ID* field_id = 0) : type_id_(type_id), field_id_(field_id) {}
: type_id_(type_id), field_id_(field_id)
{
}
const ID* type_id() const { return type_id_; } const ID* type_id() const { return type_id_; }
const ID* field_id() const { return field_id_; } const ID* field_id() const { return field_id_; }
protected: protected:
const ID *type_id_, *field_id_; const ID *type_id_, *field_id_;
}; };
#endif // pac_action_h #endif // pac_action_h

View file

@ -14,330 +14,250 @@
#include "pac_type.h" #include "pac_type.h"
#include "pac_varfield.h" #include "pac_varfield.h"
AnalyzerDecl::AnalyzerDecl(ID* id, DeclType decl_type, ParamList* params) AnalyzerDecl::AnalyzerDecl(ID* id, DeclType decl_type, ParamList* params) : TypeDecl(id, params, new DummyType()) {
: TypeDecl(id, params, new DummyType()) decl_type_ = decl_type;
{
decl_type_ = decl_type;
statevars_ = new StateVarList(); statevars_ = new StateVarList();
actions_ = new AnalyzerActionList(); actions_ = new AnalyzerActionList();
helpers_ = new AnalyzerHelperList(); helpers_ = new AnalyzerHelperList();
functions_ = new FunctionList(); functions_ = new FunctionList();
constructor_helpers_ = new AnalyzerHelperList(); constructor_helpers_ = new AnalyzerHelperList();
destructor_helpers_ = new AnalyzerHelperList(); destructor_helpers_ = new AnalyzerHelperList();
eof_helpers_ = new AnalyzerHelperList(); eof_helpers_ = new AnalyzerHelperList();
SetAnalyzerContext(); SetAnalyzerContext();
env_ = nullptr; env_ = nullptr;
} }
AnalyzerDecl::~AnalyzerDecl() AnalyzerDecl::~AnalyzerDecl() {
{ delete_list(StateVarList, statevars_);
delete_list(StateVarList, statevars_); delete_list(AnalyzerActionList, actions_);
delete_list(AnalyzerActionList, actions_); delete_list(AnalyzerHelperList, helpers_);
delete_list(AnalyzerHelperList, helpers_); delete_list(FunctionList, functions_);
delete_list(FunctionList, functions_); delete_list(ParamList, params_);
delete_list(ParamList, params_); delete_list(AnalyzerHelperList, constructor_helpers_);
delete_list(AnalyzerHelperList, constructor_helpers_); delete_list(AnalyzerHelperList, destructor_helpers_);
delete_list(AnalyzerHelperList, destructor_helpers_); delete_list(AnalyzerHelperList, eof_helpers_);
delete_list(AnalyzerHelperList, eof_helpers_); }
}
void AnalyzerDecl::AddElements(AnalyzerElementList* elemlist) void AnalyzerDecl::AddElements(AnalyzerElementList* elemlist) {
{ ASSERT(! env_);
ASSERT(! env_); foreach (i, AnalyzerElementList, elemlist) {
foreach (i, AnalyzerElementList, elemlist) AnalyzerElement* elem = *i;
{ switch ( elem->type() ) {
AnalyzerElement* elem = *i; case AnalyzerElement::STATE: {
switch ( elem->type() ) ASSERT(0);
{ AnalyzerState* state_elem = (AnalyzerState*)elem;
case AnalyzerElement::STATE: statevars_->insert(statevars_->end(), state_elem->statevars()->begin(), state_elem->statevars()->end());
{ } break;
ASSERT(0); case AnalyzerElement::ACTION: {
AnalyzerState* state_elem = (AnalyzerState*)elem; ASSERT(0);
statevars_->insert(statevars_->end(), state_elem->statevars()->begin(), AnalyzerAction* action_elem = (AnalyzerAction*)elem;
state_elem->statevars()->end()); actions_->push_back(action_elem);
} } break;
break; case AnalyzerElement::HELPER: {
case AnalyzerElement::ACTION: AnalyzerHelper* helper_elem = (AnalyzerHelper*)elem;
{
ASSERT(0);
AnalyzerAction* action_elem = (AnalyzerAction*)elem;
actions_->push_back(action_elem);
}
break;
case AnalyzerElement::HELPER:
{
AnalyzerHelper* helper_elem = (AnalyzerHelper*)elem;
switch ( helper_elem->helper_type() ) switch ( helper_elem->helper_type() ) {
{ case AnalyzerHelper::INIT_CODE: constructor_helpers_->push_back(helper_elem); break;
case AnalyzerHelper::INIT_CODE: case AnalyzerHelper::CLEANUP_CODE: destructor_helpers_->push_back(helper_elem); break;
constructor_helpers_->push_back(helper_elem); case AnalyzerHelper::EOF_CODE: eof_helpers_->push_back(helper_elem); break;
break; default: helpers_->push_back(helper_elem);
case AnalyzerHelper::CLEANUP_CODE: }
destructor_helpers_->push_back(helper_elem); } break;
break; case AnalyzerElement::FUNCTION: {
case AnalyzerHelper::EOF_CODE: AnalyzerFunction* func_elem = (AnalyzerFunction*)elem;
eof_helpers_->push_back(helper_elem); Function* func = func_elem->function();
break; func->set_analyzer_decl(this);
default: functions_->push_back(func);
helpers_->push_back(helper_elem); } break;
} case AnalyzerElement::FLOW: {
} AnalyzerFlow* flow_elem = (AnalyzerFlow*)elem;
break; ProcessFlowElement(flow_elem);
case AnalyzerElement::FUNCTION: } break;
{ case AnalyzerElement::DATAUNIT: {
AnalyzerFunction* func_elem = (AnalyzerFunction*)elem; AnalyzerDataUnit* dataunit_elem = (AnalyzerDataUnit*)elem;
Function* func = func_elem->function(); ProcessDataUnitElement(dataunit_elem);
func->set_analyzer_decl(this); } break;
functions_->push_back(func); }
} }
break; }
case AnalyzerElement::FLOW:
{
AnalyzerFlow* flow_elem = (AnalyzerFlow*)elem;
ProcessFlowElement(flow_elem);
}
break;
case AnalyzerElement::DATAUNIT:
{
AnalyzerDataUnit* dataunit_elem = (AnalyzerDataUnit*)elem;
ProcessDataUnitElement(dataunit_elem);
}
break;
}
}
}
string AnalyzerDecl::class_name() const string AnalyzerDecl::class_name() const { return id_->Name(); }
{
return id_->Name();
}
void AnalyzerDecl::Prepare() void AnalyzerDecl::Prepare() {
{ TypeDecl::Prepare();
TypeDecl::Prepare();
ASSERT(statevars_->empty()); ASSERT(statevars_->empty());
ASSERT(actions_->empty()); ASSERT(actions_->empty());
foreach (i, FunctionList, functions_) foreach (i, FunctionList, functions_) {
{ Function* function = *i;
Function* function = *i; function->Prepare(env_);
function->Prepare(env_); }
} foreach (i, StateVarList, statevars_) {
foreach (i, StateVarList, statevars_) StateVar* statevar = *i;
{ env_->AddID(statevar->id(), STATE_VAR, statevar->type());
StateVar* statevar = *i; }
env_->AddID(statevar->id(), STATE_VAR, statevar->type()); foreach (i, AnalyzerActionList, actions_) {
} AnalyzerAction* action = *i;
foreach (i, AnalyzerActionList, actions_) action->InstallHook(this);
{ }
AnalyzerAction* action = *i; }
action->InstallHook(this);
}
}
void AnalyzerDecl::GenForwardDeclaration(Output* out_h) void AnalyzerDecl::GenForwardDeclaration(Output* out_h) {
{ out_h->println("class %s;", class_name().c_str());
out_h->println("class %s;", class_name().c_str()); foreach (i, FunctionList, functions_) {
foreach (i, FunctionList, functions_) Function* function = *i;
{ function->GenForwardDeclaration(out_h);
Function* function = *i; }
function->GenForwardDeclaration(out_h); }
}
}
void AnalyzerDecl::GenActions(Output* out_h, Output* out_cc) void AnalyzerDecl::GenActions(Output* out_h, Output* out_cc) {
{ foreach (i, AnalyzerActionList, actions_) {
foreach (i, AnalyzerActionList, actions_) (*i)->GenCode(out_h, out_cc, this);
{ }
(*i)->GenCode(out_h, out_cc, this); }
}
}
void AnalyzerDecl::GenHelpers(Output* out_h, Output* out_cc) void AnalyzerDecl::GenHelpers(Output* out_h, Output* out_cc) {
{ foreach (i, AnalyzerHelperList, helpers_) {
foreach (i, AnalyzerHelperList, helpers_) (*i)->GenCode(out_h, out_cc, this);
{ }
(*i)->GenCode(out_h, out_cc, this); }
}
}
void AnalyzerDecl::GenPubDecls(Output* out_h, Output* out_cc) void AnalyzerDecl::GenPubDecls(Output* out_h, Output* out_cc) {
{ TypeDecl::GenPubDecls(out_h, out_cc);
TypeDecl::GenPubDecls(out_h, out_cc);
GenProcessFunc(out_h, out_cc); GenProcessFunc(out_h, out_cc);
GenGapFunc(out_h, out_cc); GenGapFunc(out_h, out_cc);
GenEOFFunc(out_h, out_cc); GenEOFFunc(out_h, out_cc);
out_h->println(""); out_h->println("");
if ( ! functions_->empty() ) if ( ! functions_->empty() ) {
{ out_h->println("// Functions");
out_h->println("// Functions"); GenFunctions(out_h, out_cc);
GenFunctions(out_h, out_cc); out_h->println("");
out_h->println(""); }
}
// TODO: export public state variables // TODO: export public state variables
} }
void AnalyzerDecl::GenPrivDecls(Output* out_h, Output* out_cc) void AnalyzerDecl::GenPrivDecls(Output* out_h, Output* out_cc) {
{ TypeDecl::GenPrivDecls(out_h, out_cc);
TypeDecl::GenPrivDecls(out_h, out_cc);
if ( ! helpers_->empty() ) if ( ! helpers_->empty() ) {
{ out_h->println("");
out_h->println(""); out_h->println("// Additional members");
out_h->println("// Additional members"); GenHelpers(out_h, out_cc);
GenHelpers(out_h, out_cc); }
}
// TODO: declare state variables // TODO: declare state variables
} }
void AnalyzerDecl::GenInitCode(Output* out_cc) void AnalyzerDecl::GenInitCode(Output* out_cc) {
{ TypeDecl::GenInitCode(out_cc);
TypeDecl::GenInitCode(out_cc); foreach (i, AnalyzerHelperList, constructor_helpers_) {
foreach (i, AnalyzerHelperList, constructor_helpers_) (*i)->GenCode(nullptr, out_cc, this);
{ }
(*i)->GenCode(nullptr, out_cc, this); }
}
}
void AnalyzerDecl::GenCleanUpCode(Output* out_cc) void AnalyzerDecl::GenCleanUpCode(Output* out_cc) {
{ TypeDecl::GenCleanUpCode(out_cc);
TypeDecl::GenCleanUpCode(out_cc); foreach (i, AnalyzerHelperList, destructor_helpers_) {
foreach (i, AnalyzerHelperList, destructor_helpers_) (*i)->GenCode(nullptr, out_cc, this);
{ }
(*i)->GenCode(nullptr, out_cc, this); }
}
}
void AnalyzerDecl::GenStateVarDecls(Output* out_h) void AnalyzerDecl::GenStateVarDecls(Output* out_h) {
{ foreach (i, StateVarList, statevars_) {
foreach (i, StateVarList, statevars_) StateVar* var = *i;
{ var->GenDecl(out_h, env_);
StateVar* var = *i; }
var->GenDecl(out_h, env_); }
}
}
void AnalyzerDecl::GenStateVarSetFunctions(Output* out_h) void AnalyzerDecl::GenStateVarSetFunctions(Output* out_h) {
{ foreach (i, StateVarList, statevars_) {
foreach (i, StateVarList, statevars_) StateVar* var = *i;
{ var->GenSetFunction(out_h, env_);
StateVar* var = *i; }
var->GenSetFunction(out_h, env_); }
}
}
void AnalyzerDecl::GenStateVarInitCode(Output* out_cc) void AnalyzerDecl::GenStateVarInitCode(Output* out_cc) {
{ foreach (i, StateVarList, statevars_) {
foreach (i, StateVarList, statevars_) StateVar* var = *i;
{ var->GenInitCode(out_cc, env_);
StateVar* var = *i; }
var->GenInitCode(out_cc, env_); }
}
}
void AnalyzerDecl::GenStateVarCleanUpCode(Output* out_cc) void AnalyzerDecl::GenStateVarCleanUpCode(Output* out_cc) {
{ foreach (i, StateVarList, statevars_) {
foreach (i, StateVarList, statevars_) StateVar* var = *i;
{ var->GenCleanUpCode(out_cc, env_);
StateVar* var = *i; }
var->GenCleanUpCode(out_cc, env_); }
}
}
void AnalyzerDecl::GenFunctions(Output* out_h, Output* out_cc) void AnalyzerDecl::GenFunctions(Output* out_h, Output* out_cc) {
{ foreach (i, FunctionList, functions_) {
foreach (i, FunctionList, functions_) Function* function = *i;
{ function->GenCode(out_h, out_cc);
Function* function = *i; }
function->GenCode(out_h, out_cc); }
}
}
AnalyzerState::~AnalyzerState() AnalyzerState::~AnalyzerState() {
{ // Note: do not delete elements of statevars_, because they
// Note: do not delete elements of statevars_, because they // are referenced by the AnalyzerDecl.
// are referenced by the AnalyzerDecl. delete statevars_;
delete statevars_; }
}
AnalyzerHelper::~AnalyzerHelper() AnalyzerHelper::~AnalyzerHelper() { delete code_; }
{
delete code_;
}
void AnalyzerHelper::GenCode(Output* out_h, Output* out_cc, AnalyzerDecl* decl) void AnalyzerHelper::GenCode(Output* out_h, Output* out_cc, AnalyzerDecl* decl) {
{ Output* out = nullptr;
Output* out = nullptr; switch ( helper_type_ ) {
switch ( helper_type_ ) case MEMBER_DECLS: out = out_h; break;
{ case INIT_CODE:
case MEMBER_DECLS: case CLEANUP_CODE:
out = out_h; case EOF_CODE: out = out_cc; break;
break; }
case INIT_CODE: ASSERT(out);
case CLEANUP_CODE: code()->GenCode(out, decl->env());
case EOF_CODE: }
out = out_cc;
break;
}
ASSERT(out);
code()->GenCode(out, decl->env());
}
FlowField::FlowField(ID* flow_id, ParameterizedType* flow_type) FlowField::FlowField(ID* flow_id, ParameterizedType* flow_type)
: Field(FLOW_FIELD, TYPE_NOT_TO_BE_PARSED | CLASS_MEMBER | PUBLIC_READABLE, flow_id, flow_type) : Field(FLOW_FIELD, TYPE_NOT_TO_BE_PARSED | CLASS_MEMBER | PUBLIC_READABLE, flow_id, flow_type) {}
{
}
void FlowField::GenInitCode(Output* out_cc, Env* env) void FlowField::GenInitCode(Output* out_cc, Env* env) { type_->GenPreParsing(out_cc, env); }
{
type_->GenPreParsing(out_cc, env);
}
AnalyzerFlow::AnalyzerFlow(Direction dir, ID* type_id, ExprList* params) AnalyzerFlow::AnalyzerFlow(Direction dir, ID* type_id, ExprList* params)
: AnalyzerElement(FLOW), dir_(dir), type_id_(type_id) : AnalyzerElement(FLOW), dir_(dir), type_id_(type_id) {
{ if ( ! params )
if ( ! params ) params = new ExprList();
params = new ExprList();
// Add "this" to the list of params // Add "this" to the list of params
params->insert(params->begin(), new Expr(this_id->clone())); params->insert(params->begin(), new Expr(this_id->clone()));
ID* flow_id = ((dir == UP) ? upflow_id : downflow_id)->clone(); ID* flow_id = ((dir == UP) ? upflow_id : downflow_id)->clone();
ParameterizedType* flow_type = new ParameterizedType(type_id_, params); ParameterizedType* flow_type = new ParameterizedType(type_id_, params);
flow_field_ = new FlowField(flow_id, flow_type); flow_field_ = new FlowField(flow_id, flow_type);
flow_decl_ = nullptr; flow_decl_ = nullptr;
} }
AnalyzerFlow::~AnalyzerFlow() AnalyzerFlow::~AnalyzerFlow() { delete flow_field_; }
{
delete flow_field_;
}
FlowDecl* AnalyzerFlow::flow_decl() FlowDecl* AnalyzerFlow::flow_decl() {
{ DEBUG_MSG("Getting flow_decl for %s\n", type_id_->Name());
DEBUG_MSG("Getting flow_decl for %s\n", type_id_->Name()); if ( ! flow_decl_ ) {
if ( ! flow_decl_ ) Decl* decl = Decl::LookUpDecl(type_id_);
{ if ( decl && decl->decl_type() == Decl::FLOW )
Decl* decl = Decl::LookUpDecl(type_id_); flow_decl_ = static_cast<FlowDecl*>(decl);
if ( decl && decl->decl_type() == Decl::FLOW ) if ( ! flow_decl_ ) {
flow_decl_ = static_cast<FlowDecl*>(decl); throw Exception(this, "cannot find the flow declaration");
if ( ! flow_decl_ ) }
{ }
throw Exception(this, "cannot find the flow declaration"); return flow_decl_;
} }
}
return flow_decl_;
}

View file

@ -17,162 +17,141 @@ class FlowDecl;
typedef vector<AnalyzerHelper*> AnalyzerHelperList; typedef vector<AnalyzerHelper*> AnalyzerHelperList;
typedef vector<Function*> FunctionList; typedef vector<Function*> FunctionList;
class AnalyzerDecl : public TypeDecl class AnalyzerDecl : public TypeDecl {
{
public: public:
AnalyzerDecl(ID* id, DeclType decl_type, ParamList* params); AnalyzerDecl(ID* id, DeclType decl_type, ParamList* params);
~AnalyzerDecl() override; ~AnalyzerDecl() override;
void AddElements(AnalyzerElementList* elemlist); void AddElements(AnalyzerElementList* elemlist);
void Prepare() override; void Prepare() override;
void GenForwardDeclaration(Output* out_h) override; void GenForwardDeclaration(Output* out_h) override;
// void GenCode(Output *out_h, Output *out_cc); // void GenCode(Output *out_h, Output *out_cc);
void GenInitCode(Output* out_cc) override; void GenInitCode(Output* out_cc) override;
void GenCleanUpCode(Output* out_cc) override; void GenCleanUpCode(Output* out_cc) override;
string class_name() const; string class_name() const;
// string cookie_name() const; // string cookie_name() const;
protected: protected:
virtual void ProcessFlowElement(AnalyzerFlow* flow_elem) = 0; virtual void ProcessFlowElement(AnalyzerFlow* flow_elem) = 0;
virtual void ProcessDataUnitElement(AnalyzerDataUnit* dataunit_elem) = 0; virtual void ProcessDataUnitElement(AnalyzerDataUnit* dataunit_elem) = 0;
// Generate public/private declarations for member functions and // Generate public/private declarations for member functions and
// variables // variables
void GenPubDecls(Output* out_h, Output* out_cc) override; void GenPubDecls(Output* out_h, Output* out_cc) override;
void GenPrivDecls(Output* out_h, Output* out_cc) override; void GenPrivDecls(Output* out_h, Output* out_cc) override;
// Generate the NewData() function // Generate the NewData() function
virtual void GenProcessFunc(Output* out_h, Output* out_cc) = 0; virtual void GenProcessFunc(Output* out_h, Output* out_cc) = 0;
// Generate the NewGap() function // Generate the NewGap() function
virtual void GenGapFunc(Output* out_h, Output* out_cc) = 0; virtual void GenGapFunc(Output* out_h, Output* out_cc) = 0;
// Generate the FlowEOF() function // Generate the FlowEOF() function
virtual void GenEOFFunc(Output* out_h, Output* out_cc) = 0; virtual void GenEOFFunc(Output* out_h, Output* out_cc) = 0;
// Generate the functions // Generate the functions
void GenFunctions(Output* out_h, Output* out_cc); void GenFunctions(Output* out_h, Output* out_cc);
// Generate the action functions // Generate the action functions
void GenActions(Output* out_h, Output* out_cc); void GenActions(Output* out_h, Output* out_cc);
// Generate the helper code segments // Generate the helper code segments
void GenHelpers(Output* out_h, Output* out_cc); void GenHelpers(Output* out_h, Output* out_cc);
// Generate declarations for state variables and their set functions // Generate declarations for state variables and their set functions
void GenStateVarDecls(Output* out_h); void GenStateVarDecls(Output* out_h);
void GenStateVarSetFunctions(Output* out_h); void GenStateVarSetFunctions(Output* out_h);
// Generate code for initializing and cleaning up (including // Generate code for initializing and cleaning up (including
// memory de-allocating) state variables // memory de-allocating) state variables
void GenStateVarInitCode(Output* out_cc); void GenStateVarInitCode(Output* out_cc);
void GenStateVarCleanUpCode(Output* out_cc); void GenStateVarCleanUpCode(Output* out_cc);
StateVarList* statevars_; StateVarList* statevars_;
AnalyzerActionList* actions_; AnalyzerActionList* actions_;
AnalyzerHelperList* helpers_; AnalyzerHelperList* helpers_;
FunctionList* functions_; FunctionList* functions_;
AnalyzerHelperList* constructor_helpers_; AnalyzerHelperList* constructor_helpers_;
AnalyzerHelperList* destructor_helpers_; AnalyzerHelperList* destructor_helpers_;
AnalyzerHelperList* eof_helpers_; AnalyzerHelperList* eof_helpers_;
}; };
class AnalyzerElement : public Object class AnalyzerElement : public Object {
{
public: public:
enum ElementType enum ElementType { STATE, ACTION, FUNCTION, HELPER, FLOW, DATAUNIT };
{ AnalyzerElement(ElementType type) : type_(type) {}
STATE, virtual ~AnalyzerElement() {}
ACTION,
FUNCTION,
HELPER,
FLOW,
DATAUNIT
};
AnalyzerElement(ElementType type) : type_(type) { }
virtual ~AnalyzerElement() { }
ElementType type() const { return type_; } ElementType type() const { return type_; }
private: private:
ElementType type_; ElementType type_;
}; };
// A collection of variables representing analyzer states. // A collection of variables representing analyzer states.
class AnalyzerState : public AnalyzerElement class AnalyzerState : public AnalyzerElement {
{
public: public:
AnalyzerState(StateVarList* statevars) : AnalyzerElement(STATE), statevars_(statevars) { } AnalyzerState(StateVarList* statevars) : AnalyzerElement(STATE), statevars_(statevars) {}
~AnalyzerState() override; ~AnalyzerState() override;
StateVarList* statevars() const { return statevars_; } StateVarList* statevars() const { return statevars_; }
private: private:
StateVarList* statevars_; StateVarList* statevars_;
}; };
// A collection of embedded C++ code // A collection of embedded C++ code
class AnalyzerHelper : public AnalyzerElement class AnalyzerHelper : public AnalyzerElement {
{
public: public:
enum Type enum Type {
{ MEMBER_DECLS,
MEMBER_DECLS, INIT_CODE,
INIT_CODE, CLEANUP_CODE,
CLEANUP_CODE, EOF_CODE,
EOF_CODE, };
}; AnalyzerHelper(Type helper_type, EmbeddedCode* code)
AnalyzerHelper(Type helper_type, EmbeddedCode* code) : AnalyzerElement(HELPER), helper_type_(helper_type), code_(code) {}
: AnalyzerElement(HELPER), helper_type_(helper_type), code_(code) ~AnalyzerHelper() override;
{
}
~AnalyzerHelper() override;
Type helper_type() const { return helper_type_; } Type helper_type() const { return helper_type_; }
void GenCode(Output* out_h, Output* out_cc, AnalyzerDecl* decl); void GenCode(Output* out_h, Output* out_cc, AnalyzerDecl* decl);
EmbeddedCode* code() const { return code_; } EmbeddedCode* code() const { return code_; }
private: private:
Type helper_type_; Type helper_type_;
EmbeddedCode* code_; EmbeddedCode* code_;
}; };
// The type and parameters of (uni-directional) flows of a connection. // The type and parameters of (uni-directional) flows of a connection.
class FlowField : public Field class FlowField : public Field {
{
public: public:
FlowField(ID* flow_id, ParameterizedType* flow_type); FlowField(ID* flow_id, ParameterizedType* flow_type);
void GenInitCode(Output* out, Env* env) override; void GenInitCode(Output* out, Env* env) override;
}; };
class AnalyzerFlow : public AnalyzerElement class AnalyzerFlow : public AnalyzerElement {
{
public: public:
enum Direction enum Direction { UP, DOWN };
{ AnalyzerFlow(Direction dir, ID* type_id, ExprList* params);
UP, ~AnalyzerFlow() override;
DOWN
};
AnalyzerFlow(Direction dir, ID* type_id, ExprList* params);
~AnalyzerFlow() override;
Direction dir() const { return dir_; } Direction dir() const { return dir_; }
FlowField* flow_field() const { return flow_field_; } FlowField* flow_field() const { return flow_field_; }
FlowDecl* flow_decl(); FlowDecl* flow_decl();
private: private:
Direction dir_; Direction dir_;
ID* type_id_; ID* type_id_;
FlowField* flow_field_; FlowField* flow_field_;
FlowDecl* flow_decl_; FlowDecl* flow_decl_;
}; };
#endif // pac_analyzer_h #endif // pac_analyzer_h

File diff suppressed because it is too large Load diff

View file

@ -6,82 +6,81 @@
// Fixed-length array and variable length sequence with an ending pattern // Fixed-length array and variable length sequence with an ending pattern
class ArrayType : public Type class ArrayType : public Type {
{
public: public:
ArrayType(Type* arg_elemtype, Expr* arg_length = nullptr); ArrayType(Type* arg_elemtype, Expr* arg_length = nullptr);
~ArrayType() override; ~ArrayType() override;
bool DefineValueVar() const override; bool DefineValueVar() const override;
string DataTypeStr() const override; string DataTypeStr() const override;
string DefaultValue() const override { return "0"; } string DefaultValue() const override { return "0"; }
Type* ElementDataType() const override; Type* ElementDataType() const override;
string EvalElement(const string& array, const string& index) const override; string EvalElement(const string& array, const string& index) const override;
void ProcessAttr(Attr* a) override; void ProcessAttr(Attr* a) override;
void Prepare(Env* env, int flags) override; void Prepare(Env* env, int flags) override;
void GenPubDecls(Output* out, Env* env) override; void GenPubDecls(Output* out, Env* env) override;
void GenPrivDecls(Output* out, Env* env) override; void GenPrivDecls(Output* out, Env* env) override;
void GenInitCode(Output* out, Env* env) override; void GenInitCode(Output* out, Env* env) override;
void GenCleanUpCode(Output* out, Env* env) override; void GenCleanUpCode(Output* out, Env* env) override;
int StaticSize(Env* env) const override; int StaticSize(Env* env) const override;
void SetBoundaryChecked() override; void SetBoundaryChecked() override;
void GenUntilInputCheck(Output* out_cc, Env* env); void GenUntilInputCheck(Output* out_cc, Env* env);
bool IsPointerType() const override { return true; } bool IsPointerType() const override { return true; }
protected: protected:
void init(); void init();
void DoGenParseCode(Output* out, Env* env, const DataPtr& data, int flags) override; void DoGenParseCode(Output* out, Env* env, const DataPtr& data, int flags) override;
void GenDynamicSize(Output* out, Env* env, const DataPtr& data) override; void GenDynamicSize(Output* out, Env* env, const DataPtr& data) override;
void GenArrayLength(Output* out_cc, Env* env, const DataPtr& data); void GenArrayLength(Output* out_cc, Env* env, const DataPtr& data);
string GenArrayInit(Output* out_cc, Env* env, bool known_array_length); string GenArrayInit(Output* out_cc, Env* env, bool known_array_length);
void GenElementAssignment(Output* out_cc, Env* env, string const& array_str, bool use_vector); void GenElementAssignment(Output* out_cc, Env* env, string const& array_str, bool use_vector);
void GenUntilCheck(Output* out_cc, Env* env, Expr* until_condition, bool delete_elem); void GenUntilCheck(Output* out_cc, Env* env, Expr* until_condition, bool delete_elem);
bool ByteOrderSensitive() const override { return elemtype_->RequiresByteOrder(); } bool ByteOrderSensitive() const override { return elemtype_->RequiresByteOrder(); }
bool RequiresAnalyzerContext() override; bool RequiresAnalyzerContext() override;
Type* DoClone() const override; Type* DoClone() const override;
void DoMarkIncrementalInput() override; void DoMarkIncrementalInput() override;
const ID* arraylength_var() const; const ID* arraylength_var() const;
const ID* elem_it_var() const; const ID* elem_it_var() const;
const ID* elem_var() const; const ID* elem_var() const;
const ID* elem_dataptr_var() const; const ID* elem_dataptr_var() const;
const ID* elem_input_var() const; const ID* elem_input_var() const;
protected: protected:
bool DoTraverse(DataDepVisitor* visitor) override; bool DoTraverse(DataDepVisitor* visitor) override;
private: private:
Type* elemtype_; Type* elemtype_;
Expr* length_; Expr* length_;
string vector_str_; string vector_str_;
string datatype_str_; string datatype_str_;
string end_of_array_loop_label_; string end_of_array_loop_label_;
Field* arraylength_var_field_; Field* arraylength_var_field_;
Field* elem_it_var_field_; Field* elem_it_var_field_;
Field* elem_var_field_; Field* elem_var_field_;
Field* elem_dataptr_var_field_; Field* elem_dataptr_var_field_;
Field* elem_input_var_field_; Field* elem_input_var_field_;
// This does not come from &until, but is internally generated // This does not come from &until, but is internally generated
Expr* elem_dataptr_until_expr_; Expr* elem_dataptr_until_expr_;
Expr* attr_generic_until_expr_; Expr* attr_generic_until_expr_;
Expr* attr_until_element_expr_; Expr* attr_until_element_expr_;
Expr* attr_until_input_expr_; Expr* attr_until_input_expr_;
}; };
#endif // pac_array_h #endif // pac_array_h

View file

@ -2,60 +2,47 @@
#include "pac_expr.h" #include "pac_expr.h"
bool Attr::DoTraverse(DataDepVisitor* visitor) bool Attr::DoTraverse(DataDepVisitor* visitor) {
{ if ( expr_ && ! expr_->Traverse(visitor) )
if ( expr_ && ! expr_->Traverse(visitor) ) return false;
return false; return true;
return true; }
}
bool Attr::RequiresAnalyzerContext() const bool Attr::RequiresAnalyzerContext() const { return (expr_ && expr_->RequiresAnalyzerContext()); }
{
return (expr_ && expr_->RequiresAnalyzerContext());
}
void Attr::init() void Attr::init() {
{ expr_ = nullptr;
expr_ = nullptr; seqend_ = nullptr;
seqend_ = nullptr; delete_expr_ = false;
delete_expr_ = false; }
}
Attr::Attr(AttrType type) : DataDepElement(DataDepElement::ATTR) Attr::Attr(AttrType type) : DataDepElement(DataDepElement::ATTR) {
{ type_ = type;
type_ = type; init();
init(); }
}
Attr::Attr(AttrType type, Expr* expr) : DataDepElement(DataDepElement::ATTR) Attr::Attr(AttrType type, Expr* expr) : DataDepElement(DataDepElement::ATTR) {
{ type_ = type;
type_ = type; init();
init(); expr_ = expr;
expr_ = expr; }
}
Attr::Attr(AttrType type, ExprList* exprlist) : DataDepElement(DataDepElement::ATTR) Attr::Attr(AttrType type, ExprList* exprlist) : DataDepElement(DataDepElement::ATTR) {
{ type_ = type;
type_ = type; init();
init(); expr_ = new Expr(exprlist);
expr_ = new Expr(exprlist); delete_expr_ = true;
delete_expr_ = true; }
}
Attr::Attr(AttrType type, SeqEnd* seqend) : DataDepElement(DataDepElement::ATTR) Attr::Attr(AttrType type, SeqEnd* seqend) : DataDepElement(DataDepElement::ATTR) {
{ type_ = type;
type_ = type; init();
init(); seqend_ = seqend;
seqend_ = seqend; }
}
Attr::~Attr() Attr::~Attr() {
{ if ( delete_expr_ )
if ( delete_expr_ ) delete expr_;
delete expr_; }
}
LetAttr::LetAttr(FieldList* letfields) : Attr(ATTR_LET) LetAttr::LetAttr(FieldList* letfields) : Attr(ATTR_LET) { letfields_ = letfields; }
{
letfields_ = letfields;
}

View file

@ -4,63 +4,60 @@
#include "pac_common.h" #include "pac_common.h"
#include "pac_datadep.h" #include "pac_datadep.h"
enum AttrType enum AttrType {
{ ATTR_BYTEORDER,
ATTR_BYTEORDER, ATTR_CHECK,
ATTR_CHECK, ATTR_CHUNKED,
ATTR_CHUNKED, ATTR_ENFORCE,
ATTR_ENFORCE, ATTR_EXPORTSOURCEDATA,
ATTR_EXPORTSOURCEDATA, ATTR_IF,
ATTR_IF, ATTR_LENGTH,
ATTR_LENGTH, ATTR_LET,
ATTR_LET, ATTR_LINEBREAKER,
ATTR_LINEBREAKER, ATTR_MULTILINE,
ATTR_MULTILINE, ATTR_ONELINE,
ATTR_ONELINE, ATTR_REFCOUNT,
ATTR_REFCOUNT, ATTR_REQUIRES,
ATTR_REQUIRES, ATTR_RESTOFDATA,
ATTR_RESTOFDATA, ATTR_RESTOFFLOW,
ATTR_RESTOFFLOW, ATTR_TRANSIENT,
ATTR_TRANSIENT, ATTR_UNTIL,
ATTR_UNTIL, };
};
class Attr : public Object, public DataDepElement class Attr : public Object, public DataDepElement {
{
public: public:
Attr(AttrType type); Attr(AttrType type);
Attr(AttrType type, Expr* expr); Attr(AttrType type, Expr* expr);
Attr(AttrType type, ExprList* exprlist); Attr(AttrType type, ExprList* exprlist);
Attr(AttrType type, SeqEnd* seqend); Attr(AttrType type, SeqEnd* seqend);
~Attr() override; ~Attr() override;
AttrType type() const { return type_; } AttrType type() const { return type_; }
Expr* expr() const { return expr_; } Expr* expr() const { return expr_; }
SeqEnd* seqend() const { return seqend_; } SeqEnd* seqend() const { return seqend_; }
bool RequiresAnalyzerContext() const; bool RequiresAnalyzerContext() const;
protected: protected:
bool DoTraverse(DataDepVisitor* visitor) override; bool DoTraverse(DataDepVisitor* visitor) override;
protected: protected:
void init(); void init();
AttrType type_; AttrType type_;
Expr* expr_; Expr* expr_;
SeqEnd* seqend_; SeqEnd* seqend_;
bool delete_expr_; bool delete_expr_;
}; };
class LetAttr : public Attr class LetAttr : public Attr {
{
public: public:
LetAttr(FieldList* letfields); LetAttr(FieldList* letfields);
FieldList* letfields() const { return letfields_; } FieldList* letfields() const { return letfields_; }
private: private:
FieldList* letfields_; FieldList* letfields_;
}; };
#endif // pac_attr_h #endif // pac_attr_h

View file

@ -4,125 +4,104 @@
#include "pac_id.h" #include "pac_id.h"
#include "pac_output.h" #include "pac_output.h"
Type* BuiltInType::DoClone() const Type* BuiltInType::DoClone() const { return new BuiltInType(bit_type()); }
{
return new BuiltInType(bit_type());
}
bool BuiltInType::IsNumericType() const bool BuiltInType::IsNumericType() const {
{ BITType t = bit_type();
BITType t = bit_type(); return (t == INT8 || t == INT16 || t == INT32 || t == INT64 || t == UINT8 || t == UINT16 || t == UINT32 ||
return (t == INT8 || t == INT16 || t == INT32 || t == INT64 || t == UINT8 || t == UINT16 || t == UINT64);
t == UINT32 || t == UINT64); }
}
bool BuiltInType::CompatibleBuiltInTypes(BuiltInType* type1, BuiltInType* type2) bool BuiltInType::CompatibleBuiltInTypes(BuiltInType* type1, BuiltInType* type2) {
{ return type1->IsNumericType() && type2->IsNumericType();
return type1->IsNumericType() && type2->IsNumericType(); }
}
static const char* basic_pactype_name[] = { static const char* basic_pactype_name[] = {
#define TYPE_DEF(name, pactype, ctype, size) pactype, #define TYPE_DEF(name, pactype, ctype, size) pactype,
#include "pac_type.def" #include "pac_type.def"
#undef TYPE_DEF #undef TYPE_DEF
nullptr, nullptr,
}; };
void BuiltInType::static_init() void BuiltInType::static_init() {
{ for ( int bit_type = 0; basic_pactype_name[bit_type]; ++bit_type ) {
for ( int bit_type = 0; basic_pactype_name[bit_type]; ++bit_type ) Type::AddPredefinedType(basic_pactype_name[bit_type], new BuiltInType((BITType)bit_type));
{ }
Type::AddPredefinedType(basic_pactype_name[bit_type], new BuiltInType((BITType)bit_type)); }
}
}
int BuiltInType::LookUpByName(const char* name) int BuiltInType::LookUpByName(const char* name) {
{ ASSERT(0);
ASSERT(0); for ( int i = 0; basic_pactype_name[i]; ++i )
for ( int i = 0; basic_pactype_name[i]; ++i ) if ( strcmp(basic_pactype_name[i], name) == 0 )
if ( strcmp(basic_pactype_name[i], name) == 0 ) return i;
return i; return -1;
return -1; }
}
static const char* basic_ctype_name[] = { static const char* basic_ctype_name[] = {
#define TYPE_DEF(name, pactype, ctype, size) ctype, #define TYPE_DEF(name, pactype, ctype, size) ctype,
#include "pac_type.def" #include "pac_type.def"
#undef TYPE_DEF #undef TYPE_DEF
nullptr, nullptr,
}; };
bool BuiltInType::DefineValueVar() const bool BuiltInType::DefineValueVar() const { return bit_type_ != EMPTY; }
{
return bit_type_ != EMPTY;
}
string BuiltInType::DataTypeStr() const string BuiltInType::DataTypeStr() const { return basic_ctype_name[bit_type_]; }
{
return basic_ctype_name[bit_type_];
}
int BuiltInType::StaticSize(Env* /* env */) const int BuiltInType::StaticSize(Env* /* env */) const {
{ static const size_t basic_type_size[] = {
static const size_t basic_type_size[] = {
#define TYPE_DEF(name, pactype, ctype, size) size, #define TYPE_DEF(name, pactype, ctype, size) size,
#include "pac_type.def" #include "pac_type.def"
#undef TYPE_DEF #undef TYPE_DEF
}; };
return basic_type_size[bit_type_]; return basic_type_size[bit_type_];
} }
void BuiltInType::DoMarkIncrementalInput() void BuiltInType::DoMarkIncrementalInput() {
{ if ( bit_type_ == EMPTY )
if ( bit_type_ == EMPTY ) return;
return; Type::DoMarkIncrementalInput();
Type::DoMarkIncrementalInput(); }
}
void BuiltInType::GenInitCode(Output* out_cc, Env* env) void BuiltInType::GenInitCode(Output* out_cc, Env* env) {
{ if ( bit_type_ != EMPTY )
if ( bit_type_ != EMPTY ) out_cc->println("%s = 0;", env->LValue(value_var()));
out_cc->println("%s = 0;", env->LValue(value_var())); Type::GenInitCode(out_cc, env);
Type::GenInitCode(out_cc, env); }
}
void BuiltInType::GenDynamicSize(Output* out_cc, Env* env, const DataPtr& data) void BuiltInType::GenDynamicSize(Output* out_cc, Env* env, const DataPtr& data) {
{ /* should never be called */
/* should never be called */ ASSERT(0);
ASSERT(0); }
}
void BuiltInType::DoGenParseCode(Output* out_cc, Env* env, const DataPtr& data, int flags) void BuiltInType::DoGenParseCode(Output* out_cc, Env* env, const DataPtr& data, int flags) {
{ if ( bit_type_ == EMPTY )
if ( bit_type_ == EMPTY ) return;
return;
// There is no need to generate the size variable // There is no need to generate the size variable
// out_cc->println("%s = sizeof(%s);", size_var(), DataTypeStr().c_str()); // out_cc->println("%s = sizeof(%s);", size_var(), DataTypeStr().c_str());
GenBoundaryCheck(out_cc, env, data); GenBoundaryCheck(out_cc, env, data);
if ( anonymous_value_var() ) if ( anonymous_value_var() )
return; return;
switch ( bit_type_ ) switch ( bit_type_ ) {
{ case EMPTY:
case EMPTY: // do nothing
// do nothing break;
break;
case INT8: case INT8:
case UINT8: case UINT8:
out_cc->println("%s = *((%s const *) (%s));", lvalue(), DataTypeStr().c_str(), out_cc->println("%s = *((%s const *) (%s));", lvalue(), DataTypeStr().c_str(), data.ptr_expr());
data.ptr_expr()); break;
break; case INT16:
case INT16: case UINT16:
case UINT16: case INT32:
case INT32: case UINT32:
case UINT32: case INT64:
case INT64: case UINT64:
case UINT64:
#if 0 #if 0
out_cc->println("%s = UnMarshall<%s>(%s, %s);", out_cc->println("%s = UnMarshall<%s>(%s, %s);",
lvalue(), lvalue(),
@ -130,10 +109,9 @@ void BuiltInType::DoGenParseCode(Output* out_cc, Env* env, const DataPtr& data,
data.ptr_expr(), data.ptr_expr(),
EvalByteOrder(out_cc, env).c_str()); EvalByteOrder(out_cc, env).c_str());
#else #else
out_cc->println("%s = FixByteOrder(%s, *((%s const *) (%s)));", lvalue(), out_cc->println("%s = FixByteOrder(%s, *((%s const *) (%s)));", lvalue(),
EvalByteOrder(out_cc, env).c_str(), DataTypeStr().c_str(), EvalByteOrder(out_cc, env).c_str(), DataTypeStr().c_str(), data.ptr_expr());
data.ptr_expr());
#endif #endif
break; break;
} }
} }

View file

@ -3,51 +3,46 @@
#include "pac_type.h" #include "pac_type.h"
class BuiltInType : public Type class BuiltInType : public Type {
{
public: public:
enum BITType enum BITType {
{
#define TYPE_DEF(name, pactype, ctype, size) name, #define TYPE_DEF(name, pactype, ctype, size) name,
#include "pac_type.def" #include "pac_type.def"
#undef TYPE_DEF #undef TYPE_DEF
}; };
static int LookUpByName(const char* name); static int LookUpByName(const char* name);
BuiltInType(BITType bit_type) BuiltInType(BITType bit_type) : Type(bit_type == BuiltInType::EMPTY ? Type::EMPTY : BUILTIN), bit_type_(bit_type) {}
: Type(bit_type == BuiltInType::EMPTY ? Type::EMPTY : BUILTIN), bit_type_(bit_type)
{
}
BITType bit_type() const { return bit_type_; } BITType bit_type() const { return bit_type_; }
bool IsNumericType() const override; bool IsNumericType() const override;
bool DefineValueVar() const override; bool DefineValueVar() const override;
string DataTypeStr() const override; string DataTypeStr() const override;
string DefaultValue() const override { return "0"; } string DefaultValue() const override { return "0"; }
int StaticSize(Env* env) const override; int StaticSize(Env* env) const override;
bool IsPointerType() const override { return false; } bool IsPointerType() const override { return false; }
bool ByteOrderSensitive() const override { return StaticSize(0) >= 2; } bool ByteOrderSensitive() const override { return StaticSize(0) >= 2; }
void GenInitCode(Output* out_cc, Env* env) override; void GenInitCode(Output* out_cc, Env* env) override;
void DoMarkIncrementalInput() override; void DoMarkIncrementalInput() override;
protected: protected:
void DoGenParseCode(Output* out, Env* env, const DataPtr& data, int flags) override; void DoGenParseCode(Output* out, Env* env, const DataPtr& data, int flags) override;
void GenDynamicSize(Output* out, Env* env, const DataPtr& data) override; void GenDynamicSize(Output* out, Env* env, const DataPtr& data) override;
Type* DoClone() const override; Type* DoClone() const override;
BITType bit_type_; BITType bit_type_;
public: public:
static void static_init(); static void static_init();
static bool CompatibleBuiltInTypes(BuiltInType* type1, BuiltInType* type2); static bool CompatibleBuiltInTypes(BuiltInType* type1, BuiltInType* type2);
}; };
#endif // pac_btype_h #endif // pac_btype_h

View file

@ -12,443 +12,381 @@
#include "pac_typedecl.h" #include "pac_typedecl.h"
#include "pac_utils.h" #include "pac_utils.h"
CaseType::CaseType(Expr* index_expr, CaseFieldList* cases) CaseType::CaseType(Expr* index_expr, CaseFieldList* cases) : Type(CASE), index_expr_(index_expr), cases_(cases) {
: Type(CASE), index_expr_(index_expr), cases_(cases) index_var_ = nullptr;
{ foreach (i, CaseFieldList, cases_)
index_var_ = nullptr; AddField(*i);
foreach (i, CaseFieldList, cases_) }
AddField(*i);
}
CaseType::~CaseType() CaseType::~CaseType() {
{ delete index_var_;
delete index_var_; delete index_expr_;
delete index_expr_; delete cases_;
delete cases_; }
}
void CaseType::AddCaseField(CaseField* f) void CaseType::AddCaseField(CaseField* f) {
{ // All fields must be added before Prepare()
// All fields must be added before Prepare() ASSERT(! env());
ASSERT(! env());
AddField(f); AddField(f);
cases_->push_back(f); cases_->push_back(f);
} }
bool CaseType::DefineValueVar() const bool CaseType::DefineValueVar() const { return false; }
{
return false;
}
string CaseType::DataTypeStr() const string CaseType::DataTypeStr() const {
{ ASSERT(type_decl());
ASSERT(type_decl()); return strfmt("%s *", type_decl()->class_name().c_str());
return strfmt("%s *", type_decl()->class_name().c_str()); }
}
Type* CaseType::ValueType() const Type* CaseType::ValueType() const {
{ foreach (i, CaseFieldList, cases_) {
foreach (i, CaseFieldList, cases_) CaseField* c = *i;
{ return c->type();
CaseField* c = *i; }
return c->type(); ASSERT(0);
} return nullptr;
ASSERT(0); }
return nullptr;
}
string CaseType::DefaultValue() const string CaseType::DefaultValue() const { return ValueType()->DefaultValue(); }
{
return ValueType()->DefaultValue();
}
void CaseType::Prepare(Env* env, int flags) void CaseType::Prepare(Env* env, int flags) {
{ ASSERT(flags & TO_BE_PARSED);
ASSERT(flags & TO_BE_PARSED);
index_var_ = new ID(strfmt("%s_case_index", value_var()->Name())); index_var_ = new ID(strfmt("%s_case_index", value_var()->Name()));
// Unable to get the type for index_var_ at this moment, but we'll // Unable to get the type for index_var_ at this moment, but we'll
// generate the right type based on index_expr_ later. // generate the right type based on index_expr_ later.
env->AddID(index_var_, MEMBER_VAR, nullptr); env->AddID(index_var_, MEMBER_VAR, nullptr);
// Sort the cases_ to put the default case at the end of the list // Sort the cases_ to put the default case at the end of the list
CaseFieldList::iterator default_case_it = cases_->end(); // to avoid warning CaseFieldList::iterator default_case_it = cases_->end(); // to avoid warning
CaseField* default_case = nullptr; CaseField* default_case = nullptr;
foreach (i, CaseFieldList, cases_) foreach (i, CaseFieldList, cases_) {
{ CaseField* c = *i;
CaseField* c = *i; if ( ! c->index() ) {
if ( ! c->index() ) if ( default_case )
{ throw Exception(c, "duplicate default case");
if ( default_case ) default_case_it = i;
throw Exception(c, "duplicate default case"); default_case = c;
default_case_it = i; }
default_case = c; }
} if ( default_case ) {
} cases_->erase(default_case_it);
if ( default_case ) cases_->push_back(default_case);
{ }
cases_->erase(default_case_it);
cases_->push_back(default_case);
}
foreach (i, CaseFieldList, cases_) foreach (i, CaseFieldList, cases_) {
{ CaseField* c = *i;
CaseField* c = *i; c->set_index_var(index_var_);
c->set_index_var(index_var_); c->set_case_type(this);
c->set_case_type(this); }
}
Type::Prepare(env, flags); Type::Prepare(env, flags);
} }
void CaseType::GenPrivDecls(Output* out_h, Env* env) void CaseType::GenPrivDecls(Output* out_h, Env* env) {
{ Type* t = index_expr_->DataType(env);
Type* t = index_expr_->DataType(env);
if ( t->tot() != Type::BUILTIN ) if ( t->tot() != Type::BUILTIN )
// It's a Type::EXTERN with a C++ type of "int", "bool", or "enum", // It's a Type::EXTERN with a C++ type of "int", "bool", or "enum",
// any of which will convert consistently using an int as storage type. // any of which will convert consistently using an int as storage type.
t = extern_type_int; t = extern_type_int;
out_h->println("%s %s;", t->DataTypeStr().c_str(), env->LValue(index_var_)); out_h->println("%s %s;", t->DataTypeStr().c_str(), env->LValue(index_var_));
Type::GenPrivDecls(out_h, env); Type::GenPrivDecls(out_h, env);
} }
void CaseType::GenPubDecls(Output* out_h, Env* env) void CaseType::GenPubDecls(Output* out_h, Env* env) {
{ Type* t = index_expr_->DataType(env);
Type* t = index_expr_->DataType(env);
if ( t->tot() != Type::BUILTIN ) if ( t->tot() != Type::BUILTIN )
t = extern_type_int; t = extern_type_int;
out_h->println("%s %s const { return %s; }", t->DataTypeStr().c_str(), env->RValue(index_var_), out_h->println("%s %s const { return %s; }", t->DataTypeStr().c_str(), env->RValue(index_var_),
env->LValue(index_var_)); env->LValue(index_var_));
Type::GenPubDecls(out_h, env); Type::GenPubDecls(out_h, env);
} }
void CaseType::GenInitCode(Output* out_cc, Env* env) void CaseType::GenInitCode(Output* out_cc, Env* env) {
{ out_cc->println("%s = -1;", env->LValue(index_var_));
out_cc->println("%s = -1;", env->LValue(index_var_)); Type::GenInitCode(out_cc, env);
Type::GenInitCode(out_cc, env); }
}
void CaseType::GenCleanUpCode(Output* out_cc, Env* env) void CaseType::GenCleanUpCode(Output* out_cc, Env* env) {
{ Type::GenCleanUpCode(out_cc, env);
Type::GenCleanUpCode(out_cc, env);
env->set_in_branch(true); env->set_in_branch(true);
out_cc->println("switch ( %s )", env->RValue(index_var_)); out_cc->println("switch ( %s )", env->RValue(index_var_));
out_cc->inc_indent(); out_cc->inc_indent();
out_cc->println("{"); out_cc->println("{");
foreach (i, CaseFieldList, cases_) foreach (i, CaseFieldList, cases_) {
{ CaseField* c = *i;
CaseField* c = *i; c->GenCleanUpCode(out_cc, env);
c->GenCleanUpCode(out_cc, env); }
} out_cc->println("}");
out_cc->println("}"); out_cc->dec_indent();
out_cc->dec_indent(); env->set_in_branch(false);
env->set_in_branch(false); }
}
void CaseType::DoGenParseCode(Output* out_cc, Env* env, const DataPtr& data, int flags) void CaseType::DoGenParseCode(Output* out_cc, Env* env, const DataPtr& data, int flags) {
{ if ( StaticSize(env) >= 0 )
if ( StaticSize(env) >= 0 ) GenBoundaryCheck(out_cc, env, data);
GenBoundaryCheck(out_cc, env, data);
bool compute_size_var = false; bool compute_size_var = false;
if ( ! incremental_input() ) if ( ! incremental_input() )
compute_size_var = AddSizeVar(out_cc, env); compute_size_var = AddSizeVar(out_cc, env);
out_cc->println("%s = %s;", env->LValue(index_var_), index_expr_->EvalExpr(out_cc, env)); out_cc->println("%s = %s;", env->LValue(index_var_), index_expr_->EvalExpr(out_cc, env));
env->SetEvaluated(index_var_); env->SetEvaluated(index_var_);
env->set_in_branch(true);
out_cc->println("switch ( %s )", env->RValue(index_var_));
out_cc->inc_indent();
out_cc->println("{");
bool has_default_case = false;
foreach (i, CaseFieldList, cases_)
{
CaseField* c = *i;
c->GenParseCode(out_cc, env, data, compute_size_var ? size_var() : nullptr);
if ( c->IsDefaultCase() )
has_default_case = true;
}
if ( ! has_default_case ) env->set_in_branch(true);
{ out_cc->println("switch ( %s )", env->RValue(index_var_));
out_cc->println("default:"); out_cc->inc_indent();
out_cc->inc_indent(); out_cc->println("{");
out_cc->println("throw binpac::ExceptionInvalidCaseIndex(\"%s\", (int64)%s);", bool has_default_case = false;
decl_id()->Name(), env->RValue(index_var_)); foreach (i, CaseFieldList, cases_) {
out_cc->println("break;"); CaseField* c = *i;
out_cc->dec_indent(); c->GenParseCode(out_cc, env, data, compute_size_var ? size_var() : nullptr);
} if ( c->IsDefaultCase() )
out_cc->println("}"); has_default_case = true;
out_cc->dec_indent(); }
env->set_in_branch(false);
if ( compute_size_var ) if ( ! has_default_case ) {
env->SetEvaluated(size_var()); out_cc->println("default:");
} out_cc->inc_indent();
out_cc->println("throw binpac::ExceptionInvalidCaseIndex(\"%s\", (int64)%s);", decl_id()->Name(),
env->RValue(index_var_));
out_cc->println("break;");
out_cc->dec_indent();
}
out_cc->println("}");
out_cc->dec_indent();
env->set_in_branch(false);
void CaseType::GenDynamicSize(Output* out_cc, Env* env, const DataPtr& data) if ( compute_size_var )
{ env->SetEvaluated(size_var());
GenParseCode(out_cc, env, data, 0); }
}
int CaseType::StaticSize(Env* env) const void CaseType::GenDynamicSize(Output* out_cc, Env* env, const DataPtr& data) { GenParseCode(out_cc, env, data, 0); }
{
int static_w = -1;
foreach (i, CaseFieldList, cases_)
{
CaseField* c = *i;
int w = c->StaticSize(env);
if ( w < 0 || (static_w >= 0 && w != static_w) )
return -1;
static_w = w;
}
return static_w;
}
void CaseType::SetBoundaryChecked() int CaseType::StaticSize(Env* env) const {
{ int static_w = -1;
Type::SetBoundaryChecked(); foreach (i, CaseFieldList, cases_) {
foreach (i, CaseFieldList, cases_) CaseField* c = *i;
{ int w = c->StaticSize(env);
CaseField* c = *i; if ( w < 0 || (static_w >= 0 && w != static_w) )
c->SetBoundaryChecked(); return -1;
} static_w = w;
} }
return static_w;
}
void CaseType::DoMarkIncrementalInput() void CaseType::SetBoundaryChecked() {
{ Type::SetBoundaryChecked();
foreach (i, CaseFieldList, cases_) foreach (i, CaseFieldList, cases_) {
{ CaseField* c = *i;
CaseField* c = *i; c->SetBoundaryChecked();
c->type()->MarkIncrementalInput(); }
} }
}
bool CaseType::ByteOrderSensitive() const void CaseType::DoMarkIncrementalInput() {
{ foreach (i, CaseFieldList, cases_) {
foreach (i, CaseFieldList, cases_) CaseField* c = *i;
{ c->type()->MarkIncrementalInput();
CaseField* c = *i; }
if ( c->RequiresByteOrder() ) }
return true;
} bool CaseType::ByteOrderSensitive() const {
return false; foreach (i, CaseFieldList, cases_) {
} CaseField* c = *i;
if ( c->RequiresByteOrder() )
return true;
}
return false;
}
CaseField::CaseField(ExprList* index, ID* id, Type* type) CaseField::CaseField(ExprList* index, ID* id, Type* type)
: Field(CASE_FIELD, TYPE_TO_BE_PARSED | CLASS_MEMBER | PUBLIC_READABLE, id, type), index_(index) : Field(CASE_FIELD, TYPE_TO_BE_PARSED | CLASS_MEMBER | PUBLIC_READABLE, id, type), index_(index) {
{ ASSERT(type_);
ASSERT(type_); type_->set_value_var(id, MEMBER_VAR);
type_->set_value_var(id, MEMBER_VAR); case_type_ = nullptr;
case_type_ = nullptr; index_var_ = nullptr;
index_var_ = nullptr; }
}
CaseField::~CaseField() CaseField::~CaseField() { delete_list(ExprList, index_); }
{
delete_list(ExprList, index_);
}
void GenCaseStr(ExprList* index_list, Output* out_cc, Env* env, Type* switch_type) void GenCaseStr(ExprList* index_list, Output* out_cc, Env* env, Type* switch_type) {
{ if ( index_list ) {
if ( index_list ) foreach (i, ExprList, index_list) {
{ Expr* index_expr = *i;
foreach (i, ExprList, index_list)
{
Expr* index_expr = *i;
Type* case_type = index_expr->DataType(env); Type* case_type = index_expr->DataType(env);
if ( case_type->tot() == Type::BUILTIN && case_type->StaticSize(env) > 4 ) if ( case_type->tot() == Type::BUILTIN && case_type->StaticSize(env) > 4 )
throw ExceptionInvalidCaseSizeExpr(index_expr); throw ExceptionInvalidCaseSizeExpr(index_expr);
int index_const; int index_const;
if ( ! index_expr->ConstFold(env, &index_const) )
throw ExceptionNonConstExpr(index_expr);
// External C++ types like "int", "bool", "enum" if ( ! index_expr->ConstFold(env, &index_const) )
// all use "int" type internally by default. throw ExceptionNonConstExpr(index_expr);
int case_type_width = 4;
int switch_type_width = 4;
if ( switch_type->tot() == Type::BUILTIN ) // External C++ types like "int", "bool", "enum"
switch_type_width = switch_type->StaticSize(env); // all use "int" type internally by default.
int case_type_width = 4;
int switch_type_width = 4;
if ( case_type->tot() == Type::BUILTIN ) if ( switch_type->tot() == Type::BUILTIN )
case_type_width = case_type->StaticSize(env); switch_type_width = switch_type->StaticSize(env);
if ( case_type_width > switch_type_width ) if ( case_type->tot() == Type::BUILTIN )
{ case_type_width = case_type->StaticSize(env);
BuiltInType* st = (BuiltInType*)switch_type;
if ( switch_type_width == 1 ) if ( case_type_width > switch_type_width ) {
{ BuiltInType* st = (BuiltInType*)switch_type;
if ( st->bit_type() == BuiltInType::INT8 )
{
if ( index_const < std::numeric_limits<int8_t>::min() )
throw ExceptionInvalidCaseLimitExpr(index_expr);
if ( index_const > std::numeric_limits<int8_t>::max() )
throw ExceptionInvalidCaseLimitExpr(index_expr);
}
else
{
if ( index_const < std::numeric_limits<uint8_t>::min() )
throw ExceptionInvalidCaseLimitExpr(index_expr);
if ( index_const > std::numeric_limits<uint8_t>::max() )
throw ExceptionInvalidCaseLimitExpr(index_expr);
}
}
else if ( switch_type_width == 2 )
{
if ( st->bit_type() == BuiltInType::INT16 )
{
if ( index_const < std::numeric_limits<int16_t>::min() )
throw ExceptionInvalidCaseLimitExpr(index_expr);
if ( index_const > std::numeric_limits<int16_t>::max() )
throw ExceptionInvalidCaseLimitExpr(index_expr);
}
else
{
if ( index_const < std::numeric_limits<uint16_t>::min() )
throw ExceptionInvalidCaseLimitExpr(index_expr);
if ( index_const > std::numeric_limits<uint16_t>::max() )
throw ExceptionInvalidCaseLimitExpr(index_expr);
}
}
}
// We're always using "int" for storage, so ok to just if ( switch_type_width == 1 ) {
// cast into the type used by the switch statement since if ( st->bit_type() == BuiltInType::INT8 ) {
// some unsafe stuff is already checked above. if ( index_const < std::numeric_limits<int8_t>::min() )
out_cc->println("case ((%s) %d):", switch_type->DataTypeStr().c_str(), index_const); throw ExceptionInvalidCaseLimitExpr(index_expr);
} if ( index_const > std::numeric_limits<int8_t>::max() )
} throw ExceptionInvalidCaseLimitExpr(index_expr);
else }
{ else {
out_cc->println("default:"); if ( index_const < std::numeric_limits<uint8_t>::min() )
} throw ExceptionInvalidCaseLimitExpr(index_expr);
} if ( index_const > std::numeric_limits<uint8_t>::max() )
throw ExceptionInvalidCaseLimitExpr(index_expr);
}
}
else if ( switch_type_width == 2 ) {
if ( st->bit_type() == BuiltInType::INT16 ) {
if ( index_const < std::numeric_limits<int16_t>::min() )
throw ExceptionInvalidCaseLimitExpr(index_expr);
if ( index_const > std::numeric_limits<int16_t>::max() )
throw ExceptionInvalidCaseLimitExpr(index_expr);
}
else {
if ( index_const < std::numeric_limits<uint16_t>::min() )
throw ExceptionInvalidCaseLimitExpr(index_expr);
if ( index_const > std::numeric_limits<uint16_t>::max() )
throw ExceptionInvalidCaseLimitExpr(index_expr);
}
}
else {
assert(0);
}
}
void CaseField::Prepare(Env* env) // We're always using "int" for storage, so ok to just
{ // cast into the type used by the switch statement since
ASSERT(index_var_); // some unsafe stuff is already checked above.
Field::Prepare(env); out_cc->println("case ((%s) %d):", switch_type->DataTypeStr().c_str(), index_const);
} }
}
else {
out_cc->println("default:");
}
}
void CaseField::GenPubDecls(Output* out_h, Env* env) void CaseField::Prepare(Env* env) {
{ ASSERT(index_var_);
if ( ! ((flags_ & PUBLIC_READABLE) && (flags_ & CLASS_MEMBER)) ) Field::Prepare(env);
return; }
// Skip type "empty" void CaseField::GenPubDecls(Output* out_h, Env* env) {
if ( type_->DataTypeStr().empty() ) if ( ! ((flags_ & PUBLIC_READABLE) && (flags_ & CLASS_MEMBER)) )
return; return;
out_h->println("%s %s const", type_->DataTypeConstRefStr().c_str(), env->RValue(id_)); // Skip type "empty"
if ( type_->DataTypeStr().empty() )
return;
out_h->inc_indent(); out_h->println("%s %s const", type_->DataTypeConstRefStr().c_str(), env->RValue(id_));
out_h->println("{");
if ( ! index_ ) out_h->inc_indent();
out_h->println("return %s;", lvalue()); out_h->println("{");
else
{
out_h->println("switch ( %s )", env->RValue(index_var_));
out_h->inc_indent();
out_h->println("{");
GenCaseStr(index_, out_h, env, case_type()->IndexExpr()->DataType(env));
out_h->inc_indent();
out_h->println("break; // OK");
out_h->dec_indent();
out_h->println("default:"); if ( ! index_ )
out_h->inc_indent(); out_h->println("return %s;", lvalue());
out_h->println("throw binpac::ExceptionInvalidCase(\"%s\", (int64)%s, \"%s\");", else {
id_->LocName(), env->RValue(index_var_), OrigExprList(index_).c_str()); out_h->println("switch ( %s )", env->RValue(index_var_));
out_h->println("break;"); out_h->inc_indent();
out_h->dec_indent(); out_h->println("{");
GenCaseStr(index_, out_h, env, case_type()->IndexExpr()->DataType(env));
out_h->inc_indent();
out_h->println("break; // OK");
out_h->dec_indent();
out_h->println("}"); out_h->println("default:");
out_h->dec_indent(); out_h->inc_indent();
out_h->println("throw binpac::ExceptionInvalidCase(\"%s\", (int64)%s, \"%s\");", id_->LocName(),
env->RValue(index_var_), OrigExprList(index_).c_str());
out_h->println("break;");
out_h->dec_indent();
out_h->println("return %s;", lvalue()); out_h->println("}");
} out_h->dec_indent();
out_h->println("}"); out_h->println("return %s;", lvalue());
out_h->dec_indent(); }
}
void CaseField::GenInitCode(Output* out_cc, Env* env) out_h->println("}");
{ out_h->dec_indent();
// GenCaseStr(index_, out_cc, env); }
// out_cc->inc_indent();
// out_cc->println("{");
// out_cc->println("// Initialize \"%s\"", id_->Name());
type_->GenInitCode(out_cc, env);
// out_cc->println("}");
// out_cc->println("break;");
// out_cc->dec_indent();
}
void CaseField::GenCleanUpCode(Output* out_cc, Env* env) void CaseField::GenInitCode(Output* out_cc, Env* env) {
{ // GenCaseStr(index_, out_cc, env);
GenCaseStr(index_, out_cc, env, case_type()->IndexExpr()->DataType(env)); // out_cc->inc_indent();
out_cc->inc_indent(); // out_cc->println("{");
out_cc->println("// Clean up \"%s\"", id_->Name()); // out_cc->println("// Initialize \"%s\"", id_->Name());
out_cc->println("{"); type_->GenInitCode(out_cc, env);
if ( ! anonymous_field() ) // out_cc->println("}");
type_->GenCleanUpCode(out_cc, env); // out_cc->println("break;");
out_cc->println("}"); // out_cc->dec_indent();
out_cc->println("break;"); }
out_cc->dec_indent();
}
void CaseField::GenParseCode(Output* out_cc, Env* env, const DataPtr& data, const ID* size_var) void CaseField::GenCleanUpCode(Output* out_cc, Env* env) {
{ GenCaseStr(index_, out_cc, env, case_type()->IndexExpr()->DataType(env));
GenCaseStr(index_, out_cc, env, case_type()->IndexExpr()->DataType(env)); out_cc->inc_indent();
out_cc->inc_indent(); out_cc->println("// Clean up \"%s\"", id_->Name());
out_cc->println("// Parse \"%s\"", id_->Name()); out_cc->println("{");
out_cc->println("{"); if ( ! anonymous_field() )
type_->GenCleanUpCode(out_cc, env);
out_cc->println("}");
out_cc->println("break;");
out_cc->dec_indent();
}
{ void CaseField::GenParseCode(Output* out_cc, Env* env, const DataPtr& data, const ID* size_var) {
Env case_env(env, this); GenCaseStr(index_, out_cc, env, case_type()->IndexExpr()->DataType(env));
out_cc->inc_indent();
out_cc->println("// Parse \"%s\"", id_->Name());
out_cc->println("{");
type_->GenPreParsing(out_cc, &case_env); {
type_->GenParseCode(out_cc, &case_env, data, 0); Env case_env(env, this);
if ( size_var )
{
out_cc->println("%s = %s;", case_env.LValue(size_var),
type_->DataSize(out_cc, &case_env, data).c_str());
}
if ( type_->incremental_input() )
{
ASSERT(case_type()->parsing_complete_var());
out_cc->println("%s = %s;", case_env.LValue(case_type()->parsing_complete_var()),
case_env.RValue(type_->parsing_complete_var()));
}
out_cc->println("}");
}
out_cc->println("break;"); type_->GenPreParsing(out_cc, &case_env);
out_cc->dec_indent(); type_->GenParseCode(out_cc, &case_env, data, 0);
} if ( size_var ) {
out_cc->println("%s = %s;", case_env.LValue(size_var), type_->DataSize(out_cc, &case_env, data).c_str());
}
if ( type_->incremental_input() ) {
ASSERT(case_type()->parsing_complete_var());
out_cc->println("%s = %s;", case_env.LValue(case_type()->parsing_complete_var()),
case_env.RValue(type_->parsing_complete_var()));
}
out_cc->println("}");
}
bool CaseField::DoTraverse(DataDepVisitor* visitor) out_cc->println("break;");
{ out_cc->dec_indent();
return Field::DoTraverse(visitor) && type()->Traverse(visitor); }
}
bool CaseField::RequiresAnalyzerContext() const bool CaseField::DoTraverse(DataDepVisitor* visitor) { return Field::DoTraverse(visitor) && type()->Traverse(visitor); }
{
return Field::RequiresAnalyzerContext() || type()->RequiresAnalyzerContext(); bool CaseField::RequiresAnalyzerContext() const {
} return Field::RequiresAnalyzerContext() || type()->RequiresAnalyzerContext();
}

View file

@ -6,92 +6,90 @@
#include "pac_id.h" #include "pac_id.h"
#include "pac_type.h" #include "pac_type.h"
class CaseType : public Type class CaseType : public Type {
{
public: public:
CaseType(Expr* index, CaseFieldList* cases); CaseType(Expr* index, CaseFieldList* cases);
~CaseType() override; ~CaseType() override;
void AddCaseField(CaseField* f); void AddCaseField(CaseField* f);
bool DefineValueVar() const override; bool DefineValueVar() const override;
string DataTypeStr() const override; string DataTypeStr() const override;
string DefaultValue() const override; string DefaultValue() const override;
void Prepare(Env* env, int flags) override; void Prepare(Env* env, int flags) override;
void GenPubDecls(Output* out, Env* env) override; void GenPubDecls(Output* out, Env* env) override;
void GenPrivDecls(Output* out, Env* env) override; void GenPrivDecls(Output* out, Env* env) override;
void GenInitCode(Output* out, Env* env) override; void GenInitCode(Output* out, Env* env) override;
void GenCleanUpCode(Output* out, Env* env) override; void GenCleanUpCode(Output* out, Env* env) override;
int StaticSize(Env* env) const override; int StaticSize(Env* env) const override;
void SetBoundaryChecked() override; void SetBoundaryChecked() override;
Type* ValueType() const; Type* ValueType() const;
Expr* IndexExpr() const { return index_expr_; } Expr* IndexExpr() const { return index_expr_; }
bool IsPointerType() const override { return ValueType()->IsPointerType(); } bool IsPointerType() const override { return ValueType()->IsPointerType(); }
protected: protected:
void DoGenParseCode(Output* out, Env* env, const DataPtr& data, int flags) override; void DoGenParseCode(Output* out, Env* env, const DataPtr& data, int flags) override;
void GenDynamicSize(Output* out, Env* env, const DataPtr& data) override; void GenDynamicSize(Output* out, Env* env, const DataPtr& data) override;
Type* DoClone() const override { return nullptr; } Type* DoClone() const override { return nullptr; }
void DoMarkIncrementalInput() override; void DoMarkIncrementalInput() override;
bool ByteOrderSensitive() const override; bool ByteOrderSensitive() const override;
Expr* index_expr_; Expr* index_expr_;
ID* index_var_; ID* index_var_;
CaseFieldList* cases_; CaseFieldList* cases_;
typedef map<const ID*, CaseField*, ID_ptr_cmp> member_map_t; typedef map<const ID*, CaseField*, ID_ptr_cmp> member_map_t;
member_map_t member_map_; member_map_t member_map_;
}; };
class CaseField : public Field class CaseField : public Field {
{
public: public:
CaseField(ExprList* index, ID* id, Type* type); CaseField(ExprList* index, ID* id, Type* type);
~CaseField() override; ~CaseField() override;
CaseType* case_type() const { return case_type_; } CaseType* case_type() const { return case_type_; }
void set_case_type(CaseType* t) { case_type_ = t; } void set_case_type(CaseType* t) { case_type_ = t; }
ExprList* index() const { return index_; } ExprList* index() const { return index_; }
const char* lvalue() const { return type_->lvalue(); } const char* lvalue() const { return type_->lvalue(); }
const char* CaseStr(Env* env); const char* CaseStr(Env* env);
void set_index_var(const ID* var) { index_var_ = var; } void set_index_var(const ID* var) { index_var_ = var; }
void Prepare(Env* env) override; void Prepare(Env* env) override;
void GenPubDecls(Output* out, Env* env) override; void GenPubDecls(Output* out, Env* env) override;
void GenInitCode(Output* out, Env* env) override; void GenInitCode(Output* out, Env* env) override;
void GenCleanUpCode(Output* out, Env* env) override; void GenCleanUpCode(Output* out, Env* env) override;
void GenParseCode(Output* out, Env* env, const DataPtr& data, const ID* size_var); void GenParseCode(Output* out, Env* env, const DataPtr& data, const ID* size_var);
int StaticSize(Env* env) const { return type_->StaticSize(env); } int StaticSize(Env* env) const { return type_->StaticSize(env); }
bool IsDefaultCase() const { return ! index_; } bool IsDefaultCase() const { return ! index_; }
void SetBoundaryChecked() { type_->SetBoundaryChecked(); } void SetBoundaryChecked() { type_->SetBoundaryChecked(); }
bool RequiresByteOrder() const { return type_->RequiresByteOrder(); } bool RequiresByteOrder() const { return type_->RequiresByteOrder(); }
bool RequiresAnalyzerContext() const override; bool RequiresAnalyzerContext() const override;
protected: protected:
bool DoTraverse(DataDepVisitor* visitor) override; bool DoTraverse(DataDepVisitor* visitor) override;
protected: protected:
CaseType* case_type_; CaseType* case_type_;
ExprList* index_; ExprList* index_;
const ID* index_var_; const ID* index_var_;
}; };
// Generate a list of "case X:" lines from index_list. Each index // Generate a list of "case X:" lines from index_list. Each index
// expression must be constant foldable. // expression must be constant foldable.

View file

@ -24,58 +24,54 @@ typedef vector<CVariable*> CVariableList;
// //
// 3. We do not check repeated names. // 3. We do not check repeated names.
class CClass class CClass {
{
public: public:
CClass(const string& class_name); CClass(const string& class_name);
void AddMember(CClassMember* member); void AddMember(CClassMember* member);
void AddMethod(CClassMember* method); void AddMethod(CClassMember* method);
void GenForwardDeclaration(Output* out_h); void GenForwardDeclaration(Output* out_h);
void GenCode(Output* out_h, Output* out_cc); void GenCode(Output* out_h, Output* out_cc);
protected: protected:
string class_name_; string class_name_;
CClassMemberList* members_; CClassMemberList* members_;
CClassMethodList* methods_; CClassMethodList* methods_;
}; };
class CVariable class CVariable {
{
public: public:
CClassMember(const string& name, CType* type); CClassMember(const string& name, CType* type);
string name() const { return name_; } string name() const { return name_; }
CType* type() const { return type_; } CType* type() const { return type_; }
protected: protected:
string name_; string name_;
CType* type_; CType* type_;
}; };
class CClassMember class CClassMember {
{
public: public:
CClassMember(CVariable* var); CClassMember(CVariable* var);
void GenCode(Output* out_h, Output* out_cc); void GenCode(Output* out_h, Output* out_cc);
string decl() const; string decl() const;
protected: protected:
CVariable* var_; CVariable* var_;
}; };
class CClassMethod class CClassMethod {
{
public: public:
CClassMethod(CVariable* var, CVariableList* params); CClassMethod(CVariable* var, CVariableList* params);
string decl() const; string decl() const;
protected: protected:
CVariable* var_; CVariable* var_;
CVariableList* params_; CVariableList* params_;
}; };
#endif // pac_cclass_h #endif // pac_cclass_h

View file

@ -20,25 +20,23 @@ extern int line_number;
// representing language elements -- identifiers, types, expressions, // representing language elements -- identifiers, types, expressions,
// etc. // etc.
class Object class Object {
{
public: public:
Object() Object() {
{ filename = input_filename;
filename = input_filename; line_num = line_number;
line_num = line_number; location = strfmt("%s:%d", filename.c_str(), line_number);
location = strfmt("%s:%d", filename.c_str(), line_number); }
}
~Object() { } ~Object() {}
const char* Location() const { return location.c_str(); } const char* Location() const { return location.c_str(); }
protected: protected:
string filename; string filename;
int line_num; int line_num;
string location; string location;
}; };
class ActionParam; class ActionParam;
class ActionParamType; class ActionParamType;
@ -103,17 +101,17 @@ typedef vector<Param*> ParamList;
typedef vector<RecordField*> RecordFieldList; typedef vector<RecordField*> RecordFieldList;
typedef vector<StateVar*> StateVarList; typedef vector<StateVar*> StateVarList;
#define foreach(i, ct, pc) \ #define foreach(i, ct, pc) \
if ( pc ) \ if ( pc ) \
for ( ct::iterator i = (pc)->begin(); i != (pc)->end(); ++i ) for ( ct::iterator i = (pc)->begin(); i != (pc)->end(); ++i )
#define delete_list(ct, pc) \ #define delete_list(ct, pc) \
{ \ { \
foreach (delete_list_i, ct, pc) \ foreach (delete_list_i, ct, pc) \
delete *delete_list_i; \ delete *delete_list_i; \
delete pc; \ delete pc; \
pc = 0; \ pc = 0; \
} }
// Constants // Constants
const char* const kComputeFrameLength = "compute_frame_length"; const char* const kComputeFrameLength = "compute_frame_length";

View file

@ -11,141 +11,123 @@
#include "pac_type.h" #include "pac_type.h"
ConnDecl::ConnDecl(ID* conn_id, ParamList* params, AnalyzerElementList* elemlist) ConnDecl::ConnDecl(ID* conn_id, ParamList* params, AnalyzerElementList* elemlist)
: AnalyzerDecl(conn_id, CONN, params) : AnalyzerDecl(conn_id, CONN, params) {
{ flows_[0] = flows_[1] = nullptr;
flows_[0] = flows_[1] = nullptr; AddElements(elemlist);
AddElements(elemlist); data_type_ = new ParameterizedType(conn_id->clone(), nullptr);
data_type_ = new ParameterizedType(conn_id->clone(), nullptr); }
}
ConnDecl::~ConnDecl() ConnDecl::~ConnDecl() {
{ delete flows_[0];
delete flows_[0]; delete flows_[1];
delete flows_[1]; delete data_type_;
delete data_type_; }
}
void ConnDecl::AddBaseClass(vector<string>* base_classes) const void ConnDecl::AddBaseClass(vector<string>* base_classes) const {
{ base_classes->push_back("binpac::ConnectionAnalyzer");
base_classes->push_back("binpac::ConnectionAnalyzer"); }
}
void ConnDecl::ProcessFlowElement(AnalyzerFlow* flow_elem) void ConnDecl::ProcessFlowElement(AnalyzerFlow* flow_elem) {
{ int flow_index;
int flow_index;
if ( flow_elem->dir() == AnalyzerFlow::UP ) if ( flow_elem->dir() == AnalyzerFlow::UP )
flow_index = 0; flow_index = 0;
else else
flow_index = 1; flow_index = 1;
if ( flows_[flow_index] ) if ( flows_[flow_index] ) {
{ throw Exception(flow_elem, strfmt("%sflow already defined", flow_index == 0 ? "up" : "down"));
throw Exception(flow_elem, }
strfmt("%sflow already defined", flow_index == 0 ? "up" : "down"));
}
flows_[flow_index] = flow_elem; flows_[flow_index] = flow_elem;
type_->AddField(flow_elem->flow_field()); type_->AddField(flow_elem->flow_field());
} }
void ConnDecl::ProcessDataUnitElement(AnalyzerDataUnit* dataunit_elem) void ConnDecl::ProcessDataUnitElement(AnalyzerDataUnit* dataunit_elem) {
{ throw Exception(dataunit_elem, "dataunit should be defined in only a flow declaration");
throw Exception(dataunit_elem, "dataunit should be defined in only a flow declaration"); }
}
void ConnDecl::Prepare() void ConnDecl::Prepare() {
{ AnalyzerDecl::Prepare();
AnalyzerDecl::Prepare();
flows_[0]->flow_decl()->set_conn_decl(this); flows_[0]->flow_decl()->set_conn_decl(this);
flows_[1]->flow_decl()->set_conn_decl(this); flows_[1]->flow_decl()->set_conn_decl(this);
} }
void ConnDecl::GenPubDecls(Output* out_h, Output* out_cc) void ConnDecl::GenPubDecls(Output* out_h, Output* out_cc) { AnalyzerDecl::GenPubDecls(out_h, out_cc); }
{
AnalyzerDecl::GenPubDecls(out_h, out_cc);
}
void ConnDecl::GenPrivDecls(Output* out_h, Output* out_cc) void ConnDecl::GenPrivDecls(Output* out_h, Output* out_cc) { AnalyzerDecl::GenPrivDecls(out_h, out_cc); }
{
AnalyzerDecl::GenPrivDecls(out_h, out_cc);
}
void ConnDecl::GenEOFFunc(Output* out_h, Output* out_cc) void ConnDecl::GenEOFFunc(Output* out_h, Output* out_cc) {
{ string proto = strfmt("%s(bool is_orig)", kFlowEOF);
string proto = strfmt("%s(bool is_orig)", kFlowEOF);
out_h->println("void %s;", proto.c_str()); out_h->println("void %s;", proto.c_str());
out_cc->println("void %s::%s", class_name().c_str(), proto.c_str()); out_cc->println("void %s::%s", class_name().c_str(), proto.c_str());
out_cc->inc_indent(); out_cc->inc_indent();
out_cc->println("{"); out_cc->println("{");
out_cc->println("if ( is_orig )"); out_cc->println("if ( is_orig )");
out_cc->inc_indent(); out_cc->inc_indent();
out_cc->println("%s->%s();", env_->LValue(upflow_id), kFlowEOF); out_cc->println("%s->%s();", env_->LValue(upflow_id), kFlowEOF);
out_cc->dec_indent(); out_cc->dec_indent();
out_cc->println("else"); out_cc->println("else");
out_cc->inc_indent(); out_cc->inc_indent();
out_cc->println("%s->%s();", env_->LValue(downflow_id), kFlowEOF); out_cc->println("%s->%s();", env_->LValue(downflow_id), kFlowEOF);
foreach (i, AnalyzerHelperList, eof_helpers_) foreach (i, AnalyzerHelperList, eof_helpers_) {
{ (*i)->GenCode(nullptr, out_cc, this);
(*i)->GenCode(nullptr, out_cc, this); }
}
out_cc->dec_indent(); out_cc->dec_indent();
out_cc->println("}"); out_cc->println("}");
out_cc->dec_indent(); out_cc->dec_indent();
out_cc->println(""); out_cc->println("");
} }
void ConnDecl::GenGapFunc(Output* out_h, Output* out_cc) void ConnDecl::GenGapFunc(Output* out_h, Output* out_cc) {
{ string proto = strfmt("%s(bool is_orig, int gap_length)", kFlowGap);
string proto = strfmt("%s(bool is_orig, int gap_length)", kFlowGap);
out_h->println("void %s;", proto.c_str()); out_h->println("void %s;", proto.c_str());
out_cc->println("void %s::%s", class_name().c_str(), proto.c_str()); out_cc->println("void %s::%s", class_name().c_str(), proto.c_str());
out_cc->inc_indent(); out_cc->inc_indent();
out_cc->println("{"); out_cc->println("{");
out_cc->println("if ( is_orig )"); out_cc->println("if ( is_orig )");
out_cc->inc_indent(); out_cc->inc_indent();
out_cc->println("%s->%s(gap_length);", env_->LValue(upflow_id), kFlowGap); out_cc->println("%s->%s(gap_length);", env_->LValue(upflow_id), kFlowGap);
out_cc->dec_indent(); out_cc->dec_indent();
out_cc->println("else"); out_cc->println("else");
out_cc->inc_indent(); out_cc->inc_indent();
out_cc->println("%s->%s(gap_length);", env_->LValue(downflow_id), kFlowGap); out_cc->println("%s->%s(gap_length);", env_->LValue(downflow_id), kFlowGap);
out_cc->dec_indent(); out_cc->dec_indent();
out_cc->println("}"); out_cc->println("}");
out_cc->dec_indent(); out_cc->dec_indent();
out_cc->println(""); out_cc->println("");
} }
void ConnDecl::GenProcessFunc(Output* out_h, Output* out_cc) void ConnDecl::GenProcessFunc(Output* out_h, Output* out_cc) {
{ string proto = strfmt("%s(bool is_orig, const_byteptr begin, const_byteptr end)", kNewData);
string proto = strfmt("%s(bool is_orig, const_byteptr begin, const_byteptr end)", kNewData);
out_h->println("void %s;", proto.c_str()); out_h->println("void %s;", proto.c_str());
out_cc->println("void %s::%s", class_name().c_str(), proto.c_str()); out_cc->println("void %s::%s", class_name().c_str(), proto.c_str());
out_cc->inc_indent(); out_cc->inc_indent();
out_cc->println("{"); out_cc->println("{");
out_cc->println("if ( is_orig )"); out_cc->println("if ( is_orig )");
out_cc->inc_indent(); out_cc->inc_indent();
out_cc->println("%s->%s(begin, end);", env_->LValue(upflow_id), kNewData); out_cc->println("%s->%s(begin, end);", env_->LValue(upflow_id), kNewData);
out_cc->dec_indent(); out_cc->dec_indent();
out_cc->println("else"); out_cc->println("else");
out_cc->inc_indent(); out_cc->inc_indent();
out_cc->println("%s->%s(begin, end);", env_->LValue(downflow_id), kNewData); out_cc->println("%s->%s(begin, end);", env_->LValue(downflow_id), kNewData);
out_cc->dec_indent(); out_cc->dec_indent();
out_cc->println("}"); out_cc->println("}");
out_cc->dec_indent(); out_cc->dec_indent();
out_cc->println(""); out_cc->println("");
} }

View file

@ -4,31 +4,30 @@
#include "pac_analyzer.h" #include "pac_analyzer.h"
#include "pac_decl.h" #include "pac_decl.h"
class ConnDecl : public AnalyzerDecl class ConnDecl : public AnalyzerDecl {
{
public: public:
ConnDecl(ID* conn_id, ParamList* params, AnalyzerElementList* elemlist); ConnDecl(ID* conn_id, ParamList* params, AnalyzerElementList* elemlist);
~ConnDecl() override; ~ConnDecl() override;
void Prepare() override; void Prepare() override;
Type* DataType() const { return data_type_; } Type* DataType() const { return data_type_; }
protected: protected:
void AddBaseClass(vector<string>* base_classes) const override; void AddBaseClass(vector<string>* base_classes) const override;
void GenProcessFunc(Output* out_h, Output* out_cc) override; void GenProcessFunc(Output* out_h, Output* out_cc) override;
void GenGapFunc(Output* out_h, Output* out_cc) override; void GenGapFunc(Output* out_h, Output* out_cc) override;
void GenEOFFunc(Output* out_h, Output* out_cc) override; void GenEOFFunc(Output* out_h, Output* out_cc) override;
void GenPubDecls(Output* out_h, Output* out_cc) override; void GenPubDecls(Output* out_h, Output* out_cc) override;
void GenPrivDecls(Output* out_h, Output* out_cc) override; void GenPrivDecls(Output* out_h, Output* out_cc) override;
void ProcessFlowElement(AnalyzerFlow* flow_elem) override; void ProcessFlowElement(AnalyzerFlow* flow_elem) override;
void ProcessDataUnitElement(AnalyzerDataUnit* dataunit_elem) override; void ProcessDataUnitElement(AnalyzerDataUnit* dataunit_elem) override;
AnalyzerFlow* flows_[2]; AnalyzerFlow* flows_[2];
Type* data_type_; Type* data_type_;
}; };
#endif // pac_conn_h #endif // pac_conn_h

View file

@ -12,99 +12,83 @@
#include "pac_utils.h" #include "pac_utils.h"
ContextField::ContextField(ID* id, Type* type) ContextField::ContextField(ID* id, Type* type)
: Field(CONTEXT_FIELD, TYPE_NOT_TO_BE_PARSED | CLASS_MEMBER | PUBLIC_READABLE, id, type) : Field(CONTEXT_FIELD, TYPE_NOT_TO_BE_PARSED | CLASS_MEMBER | PUBLIC_READABLE, id, type) {}
{
}
AnalyzerContextDecl* AnalyzerContextDecl::current_analyzer_context_ = nullptr; AnalyzerContextDecl* AnalyzerContextDecl::current_analyzer_context_ = nullptr;
namespace namespace {
{ ParamList* ContextFieldsToParams(ContextFieldList* context_fields) {
ParamList* ContextFieldsToParams(ContextFieldList* context_fields) // Convert context fields to parameters
{ ParamList* params = new ParamList();
// Convert context fields to parameters foreach (i, ContextFieldList, context_fields) {
ParamList* params = new ParamList(); ContextField* f = *i;
foreach (i, ContextFieldList, context_fields) params->push_back(new Param(f->id()->clone(), f->type()));
{ }
ContextField* f = *i; return params;
params->push_back(new Param(f->id()->clone(), f->type())); }
} } // namespace
return params;
}
} // namespace private
AnalyzerContextDecl::AnalyzerContextDecl(ID* id, ContextFieldList* context_fields) AnalyzerContextDecl::AnalyzerContextDecl(ID* id, ContextFieldList* context_fields)
: TypeDecl(new ID(strfmt("Context%s", id->Name())), ContextFieldsToParams(context_fields), : TypeDecl(new ID(strfmt("Context%s", id->Name())), ContextFieldsToParams(context_fields), new DummyType()) {
new DummyType()) context_name_id_ = id;
{ if ( current_analyzer_context_ != nullptr ) {
context_name_id_ = id; throw Exception(this, strfmt("multiple declaration of analyzer context; "
if ( current_analyzer_context_ != nullptr ) "the previous one is `%s'",
{ current_analyzer_context_->id()->Name()));
throw Exception(this, strfmt("multiple declaration of analyzer context; " }
"the previous one is `%s'", else
current_analyzer_context_->id()->Name())); current_analyzer_context_ = this;
}
else
current_analyzer_context_ = this;
context_fields_ = context_fields; context_fields_ = context_fields;
param_type_ = new ParameterizedType(id_->clone(), nullptr); param_type_ = new ParameterizedType(id_->clone(), nullptr);
flow_buffer_added_ = false; flow_buffer_added_ = false;
DEBUG_MSG("Context type: %s\n", param_type()->class_name().c_str()); DEBUG_MSG("Context type: %s\n", param_type()->class_name().c_str());
} }
AnalyzerContextDecl::~AnalyzerContextDecl() AnalyzerContextDecl::~AnalyzerContextDecl() {
{ delete context_name_id_;
delete context_name_id_; delete param_type_;
delete param_type_; delete_list(ContextFieldList, context_fields_);
delete_list(ContextFieldList, context_fields_); }
}
void AnalyzerContextDecl::GenForwardDeclaration(Output* out_h) void AnalyzerContextDecl::GenForwardDeclaration(Output* out_h) {
{ GenNamespaceBegin(out_h);
GenNamespaceBegin(out_h); TypeDecl::GenForwardDeclaration(out_h);
TypeDecl::GenForwardDeclaration(out_h); }
}
void AnalyzerContextDecl::GenCode(Output* out_h, Output* out_cc) void AnalyzerContextDecl::GenCode(Output* out_h, Output* out_cc) {
{ GenNamespaceBegin(out_h);
GenNamespaceBegin(out_h); GenNamespaceBegin(out_cc);
GenNamespaceBegin(out_cc); TypeDecl::GenCode(out_h, out_cc);
TypeDecl::GenCode(out_h, out_cc); }
}
void AnalyzerContextDecl::GenNamespaceBegin(Output* out) const void AnalyzerContextDecl::GenNamespaceBegin(Output* out) const {
{ out->println("namespace %s {", context_name_id()->Name());
out->println("namespace %s {", context_name_id()->Name()); }
}
void AnalyzerContextDecl::GenNamespaceEnd(Output* out) const void AnalyzerContextDecl::GenNamespaceEnd(Output* out) const {
{ out->println("} // namespace %s", context_name_id()->Name());
out->println("} // namespace %s", context_name_id()->Name()); }
}
void AnalyzerContextDecl::AddFlowBuffer() void AnalyzerContextDecl::AddFlowBuffer() {
{ if ( flow_buffer_added_ )
if ( flow_buffer_added_ ) return;
return;
AddParam(new Param(new ID(kFlowBufferVar), FlowDecl::flow_buffer_type()->Clone())); AddParam(new Param(new ID(kFlowBufferVar), FlowDecl::flow_buffer_type()->Clone()));
flow_buffer_added_ = true; flow_buffer_added_ = true;
} }
string AnalyzerContextDecl::mb_buffer(Env* env) string AnalyzerContextDecl::mb_buffer(Env* env) {
{ // A hack. The orthodox way would be to build an Expr of
// A hack. The orthodox way would be to build an Expr of // context.flow_buffer_var, and then EvalExpr.
// context.flow_buffer_var, and then EvalExpr. return strfmt("%s->%s()", env->RValue(analyzer_context_id), kFlowBufferVar);
return strfmt("%s->%s()", env->RValue(analyzer_context_id), kFlowBufferVar); }
}
Type* DummyType::DoClone() const Type* DummyType::DoClone() const {
{ // Fields will be copied in Type::Clone().
// Fields will be copied in Type::Clone(). return new DummyType();
return new DummyType(); }
}

View file

@ -23,84 +23,75 @@
// accessed as members of the cookie, such as // accessed as members of the cookie, such as
// ``binpac_context.connection''. // ``binpac_context.connection''.
class ContextField : public Field class ContextField : public Field {
{
public: public:
ContextField(ID* id, Type* type); ContextField(ID* id, Type* type);
}; };
class AnalyzerContextDecl : public TypeDecl class AnalyzerContextDecl : public TypeDecl {
{
public: public:
AnalyzerContextDecl(ID* id, ContextFieldList* context_fields); AnalyzerContextDecl(ID* id, ContextFieldList* context_fields);
~AnalyzerContextDecl() override; ~AnalyzerContextDecl() override;
void AddFlowBuffer(); void AddFlowBuffer();
const ID* context_name_id() const { return context_name_id_; } const ID* context_name_id() const { return context_name_id_; }
// The type of analyzer context as a parameter // The type of analyzer context as a parameter
ParameterizedType* param_type() const { return param_type_; } ParameterizedType* param_type() const { return param_type_; }
void GenForwardDeclaration(Output* out_h) override; void GenForwardDeclaration(Output* out_h) override;
void GenCode(Output* out_h, Output* out_cc) override; void GenCode(Output* out_h, Output* out_cc) override;
void GenNamespaceBegin(Output* out) const; void GenNamespaceBegin(Output* out) const;
void GenNamespaceEnd(Output* out) const; void GenNamespaceEnd(Output* out) const;
private: private:
ID* context_name_id_; ID* context_name_id_;
ContextFieldList* context_fields_; ContextFieldList* context_fields_;
ParameterizedType* param_type_; ParameterizedType* param_type_;
bool flow_buffer_added_; bool flow_buffer_added_;
// static members // static members
public: public:
static AnalyzerContextDecl* current_analyzer_context() { return current_analyzer_context_; } static AnalyzerContextDecl* current_analyzer_context() { return current_analyzer_context_; }
static string mb_buffer(Env* env); static string mb_buffer(Env* env);
private: private:
static AnalyzerContextDecl* current_analyzer_context_; static AnalyzerContextDecl* current_analyzer_context_;
}; };
class DummyType : public Type class DummyType : public Type {
{
public: public:
DummyType() : Type(DUMMY) { } DummyType() : Type(DUMMY) {}
bool DefineValueVar() const override { return false; } bool DefineValueVar() const override { return false; }
string DataTypeStr() const override string DataTypeStr() const override {
{ ASSERT(0);
ASSERT(0); return "";
return ""; }
}
int StaticSize(Env* env) const override int StaticSize(Env* env) const override {
{ ASSERT(0);
ASSERT(0); return -1;
return -1; }
}
bool ByteOrderSensitive() const override { return false; } bool ByteOrderSensitive() const override { return false; }
bool IsPointerType() const override bool IsPointerType() const override {
{ ASSERT(0);
ASSERT(0); return false;
return false; }
}
void DoGenParseCode(Output* out, Env* env, const DataPtr& data, int flags) override void DoGenParseCode(Output* out, Env* env, const DataPtr& data, int flags) override { ASSERT(0); }
{
ASSERT(0);
}
// Generate code for computing the dynamic size of the type // Generate code for computing the dynamic size of the type
void GenDynamicSize(Output* out, Env* env, const DataPtr& data) override { ASSERT(0); } void GenDynamicSize(Output* out, Env* env, const DataPtr& data) override { ASSERT(0); }
protected: protected:
Type* DoClone() const override; Type* DoClone() const override;
void DoMarkIncrementalInput() override { ASSERT(0); } void DoMarkIncrementalInput() override { ASSERT(0); }
}; };
#endif // pac_context_h #endif // pac_context_h

View file

@ -3,129 +3,108 @@
#include "pac_dbg.h" #include "pac_dbg.h"
#include "pac_exception.h" #include "pac_exception.h"
namespace namespace {
{
class EscapeException class EscapeException {
{
public: public:
explicit EscapeException(const string& s) { msg_ = s; } explicit EscapeException(const string& s) { msg_ = s; }
const string& msg() const { return msg_; } const string& msg() const { return msg_; }
private: private:
string msg_; string msg_;
}; };
// Copied from util.cc of Zeek // Copied from util.cc of Zeek
int expand_escape(const char*& s) int expand_escape(const char*& s) {
{ switch ( *(s++) ) {
switch ( *(s++) ) case 'b': return '\b';
{ case 'f': return '\f';
case 'b': case 'n': return '\n';
return '\b'; case 'r': return '\r';
case 'f': case 't': return '\t';
return '\f'; case 'a': return '\a';
case 'n': case 'v': return '\v';
return '\n';
case 'r':
return '\r';
case 't':
return '\t';
case 'a':
return '\a';
case 'v':
return '\v';
case '0': case '0':
case '1': case '1':
case '2': case '2':
case '3': case '3':
case '4': case '4':
case '5': case '5':
case '6': case '6':
case '7': case '7': { // \<octal>{1,3}
{ // \<octal>{1,3} --s; // put back the first octal digit
--s; // put back the first octal digit const char* start = s;
const char* start = s;
// Don't increment inside loop control // Don't increment inside loop control
// because if isdigit() is a macro it might // because if isdigit() is a macro it might
// expand into multiple increments ... // expand into multiple increments ...
// Here we define a maximum length for escape sequence // Here we define a maximum length for escape sequence
// to allow easy handling of string like: "^H0" as // to allow easy handling of string like: "^H0" as
// "\0100". // "\0100".
for ( int len = 0; len < 3 && isascii(*s) && isdigit(*s); ++s, ++len ) for ( int len = 0; len < 3 && isascii(*s) && isdigit(*s); ++s, ++len )
; ;
int result; int result;
if ( sscanf(start, "%3o", &result) != 1 ) if ( sscanf(start, "%3o", &result) != 1 )
throw EscapeException(strfmt("bad octal escape: \"%s", start)); throw EscapeException(strfmt("bad octal escape: \"%s", start));
return result; return result;
} }
case 'x': case 'x': { /* \x<hex> */
{ /* \x<hex> */ const char* start = s;
const char* start = s;
// Look at most 2 characters, so that "\x0ddir" -> "^Mdir". // Look at most 2 characters, so that "\x0ddir" -> "^Mdir".
for ( int len = 0; len < 2 && isascii(*s) && isxdigit(*s); ++s, ++len ) for ( int len = 0; len < 2 && isascii(*s) && isxdigit(*s); ++s, ++len )
; ;
int result; int result;
if ( sscanf(start, "%2x", &result) != 1 ) if ( sscanf(start, "%2x", &result) != 1 )
throw EscapeException(strfmt("bad hexadecimal escape: \"%s", start)); throw EscapeException(strfmt("bad hexadecimal escape: \"%s", start));
return result; return result;
} }
default: default: return s[-1];
return s[-1]; }
} }
}
} // private namespace } // namespace
ConstString::ConstString(const string& s) : str_(s) ConstString::ConstString(const string& s) : str_(s) {
{ // Copied from scan.l of Zeek
// Copied from scan.l of Zeek try {
try const char* text = str_.c_str();
{ int len = strlen(text) + 1;
const char* text = str_.c_str(); int i = 0;
int len = strlen(text) + 1;
int i = 0;
char* new_s = new char[len]; char* new_s = new char[len];
// Skip leading quote. // Skip leading quote.
for ( ++text; *text; ++text ) for ( ++text; *text; ++text ) {
{ if ( *text == '\\' ) {
if ( *text == '\\' ) ++text; // skip '\'
{ new_s[i++] = expand_escape(text);
++text; // skip '\' --text; // point to end of sequence
new_s[i++] = expand_escape(text); }
--text; // point to end of sequence else {
} new_s[i++] = *text;
else }
{ }
new_s[i++] = *text; ASSERT(i < len);
}
}
ASSERT(i < len);
// Get rid of trailing quote. // Get rid of trailing quote.
ASSERT(new_s[i - 1] == '"'); ASSERT(new_s[i - 1] == '"');
new_s[i - 1] = '\0'; new_s[i - 1] = '\0';
unescaped_ = new_s; unescaped_ = new_s;
delete[] new_s; delete[] new_s;
} } catch ( EscapeException const& e ) {
catch ( EscapeException const& e ) // Throw again with the object
{ throw Exception(this, e.msg().c_str());
// Throw again with the object }
throw Exception(this, e.msg().c_str()); }
}
}

View file

@ -3,21 +3,20 @@
#include "pac_common.h" #include "pac_common.h"
class ConstString : public Object class ConstString : public Object {
{
public: public:
ConstString(const string& s); ConstString(const string& s);
// The string in its escaped form, with surrounding '"'s // The string in its escaped form, with surrounding '"'s
const string& str() const { return str_; } const string& str() const { return str_; }
const char* c_str() const { return str_.c_str(); } const char* c_str() const { return str_.c_str(); }
// The unescaped string, without surrounding '"'s // The unescaped string, without surrounding '"'s
const string& unescaped() const { return unescaped_; } const string& unescaped() const { return unescaped_; }
private: private:
string str_; string str_;
string unescaped_; string unescaped_;
}; };
#endif // pac_cstr_h #endif // pac_cstr_h

View file

@ -1,21 +1,13 @@
#include "pac_ctype.h" #include "pac_ctype.h"
string CType::DeclareInstance(const string& var) const string CType::DeclareInstance(const string& var) const { return strfmt("%s %s", name().c_str(), var.c_str()); }
{
return strfmt("%s %s", name().c_str(), var.c_str());
}
string CType::DeclareConstReference(const string& var) const string CType::DeclareConstReference(const string& var) const {
{ return strfmt("%s const &%s", name().c_str(), var.c_str());
return strfmt("%s const &%s", name().c_str(), var.c_str()); }
}
string CType::DeclareConstPointer(const string& var) const string CType::DeclareConstPointer(const string& var) const {
{ return strfmt("%s const *%s", name().c_str(), var.c_str());
return strfmt("%s const *%s", name().c_str(), var.c_str()); }
}
string CType::DeclarePointer(const string& var) const string CType::DeclarePointer(const string& var) const { return strfmt("%s *%s", name().c_str(), var.c_str()); }
{
return strfmt("%s *%s", name().c_str(), var.c_str());
}

View file

@ -4,20 +4,19 @@
#include "pac_common.h" #include "pac_common.h"
// Represents a C++ type // Represents a C++ type
class CType class CType {
{
public: public:
CType(const string& name); CType(const string& name);
string name() const { return name_; } string name() const { return name_; }
string DeclareInstance(const string& var) const; string DeclareInstance(const string& var) const;
string DeclareConstReference(const string& var) const; string DeclareConstReference(const string& var) const;
string DeclareConstPointer(const string& var) const; string DeclareConstPointer(const string& var) const;
string DeclarePointer(const string& var) const; string DeclarePointer(const string& var) const;
protected: protected:
string name_; string name_;
}; };
#endif // pac_ctype_h #endif // pac_ctype_h

View file

@ -4,70 +4,51 @@
#include "pac_id.h" #include "pac_id.h"
#include "pac_type.h" #include "pac_type.h"
DataDepElement::DataDepElement(DDE_Type type) : dde_type_(type), in_traversal(false) { } DataDepElement::DataDepElement(DDE_Type type) : dde_type_(type), in_traversal(false) {}
bool DataDepElement::Traverse(DataDepVisitor* visitor) bool DataDepElement::Traverse(DataDepVisitor* visitor) {
{ // Avoid infinite loop
// Avoid infinite loop if ( in_traversal )
if ( in_traversal ) return true;
return true; if ( ! visitor->PreProcess(this) )
if ( ! visitor->PreProcess(this) ) return false;
return false;
in_traversal = true; in_traversal = true;
bool cont = DoTraverse(visitor); bool cont = DoTraverse(visitor);
in_traversal = false; in_traversal = false;
if ( ! cont ) if ( ! cont )
return false; return false;
if ( ! visitor->PostProcess(this) ) if ( ! visitor->PostProcess(this) )
return false; return false;
return true; return true;
} }
Expr* DataDepElement::expr() Expr* DataDepElement::expr() { return static_cast<Expr*>(this); }
{
return static_cast<Expr*>(this);
}
Type* DataDepElement::type() Type* DataDepElement::type() { return static_cast<Type*>(this); }
{
return static_cast<Type*>(this);
}
bool RequiresAnalyzerContext::PreProcess(DataDepElement* element) bool RequiresAnalyzerContext::PreProcess(DataDepElement* element) {
{ switch ( element->dde_type() ) {
switch ( element->dde_type() ) case DataDepElement::EXPR: ProcessExpr(element->expr()); break;
{ default: break;
case DataDepElement::EXPR: }
ProcessExpr(element->expr());
break;
default:
break;
}
// Continue traversal until we know the answer is 'yes' // Continue traversal until we know the answer is 'yes'
return ! requires_analyzer_context_; return ! requires_analyzer_context_;
} }
bool RequiresAnalyzerContext::PostProcess(DataDepElement* element) bool RequiresAnalyzerContext::PostProcess(DataDepElement* element) { return ! requires_analyzer_context_; }
{
return ! requires_analyzer_context_;
}
void RequiresAnalyzerContext::ProcessExpr(Expr* expr) void RequiresAnalyzerContext::ProcessExpr(Expr* expr) {
{ if ( expr->expr_type() == Expr::EXPR_ID ) {
if ( expr->expr_type() == Expr::EXPR_ID ) requires_analyzer_context_ =
{ (requires_analyzer_context_ || *expr->id() == *analyzer_context_id || *expr->id() == *context_macro_id);
requires_analyzer_context_ = (requires_analyzer_context_ || }
*expr->id() == *analyzer_context_id || }
*expr->id() == *context_macro_id);
}
}
bool RequiresAnalyzerContext::compute(DataDepElement* element) bool RequiresAnalyzerContext::compute(DataDepElement* element) {
{ RequiresAnalyzerContext visitor;
RequiresAnalyzerContext visitor; element->Traverse(&visitor);
element->Traverse(&visitor); return visitor.requires_analyzer_context_;
return visitor.requires_analyzer_context_; }
}

View file

@ -9,64 +9,60 @@
class DataDepVisitor; class DataDepVisitor;
class DataDepElement class DataDepElement {
{
public: public:
enum DDE_Type enum DDE_Type {
{ ATTR,
ATTR, CASEEXPR,
CASEEXPR, EXPR,
EXPR, FIELD,
FIELD, INPUT_BUFFER,
INPUT_BUFFER, PARAM,
PARAM, TYPE,
TYPE, };
};
DataDepElement(DDE_Type type); DataDepElement(DDE_Type type);
virtual ~DataDepElement() { } virtual ~DataDepElement() {}
// Returns whether to continue traversal // Returns whether to continue traversal
bool Traverse(DataDepVisitor* visitor); bool Traverse(DataDepVisitor* visitor);
// Returns whether to continue traversal // Returns whether to continue traversal
virtual bool DoTraverse(DataDepVisitor* visitor) = 0; virtual bool DoTraverse(DataDepVisitor* visitor) = 0;
DDE_Type dde_type() const { return dde_type_; } DDE_Type dde_type() const { return dde_type_; }
Expr* expr(); Expr* expr();
Type* type(); Type* type();
protected: protected:
DDE_Type dde_type_; DDE_Type dde_type_;
bool in_traversal; bool in_traversal;
}; };
class DataDepVisitor class DataDepVisitor {
{
public: public:
virtual ~DataDepVisitor() { } virtual ~DataDepVisitor() {}
// Returns whether to continue traversal // Returns whether to continue traversal
virtual bool PreProcess(DataDepElement* element) = 0; virtual bool PreProcess(DataDepElement* element) = 0;
virtual bool PostProcess(DataDepElement* element) = 0; virtual bool PostProcess(DataDepElement* element) = 0;
}; };
class RequiresAnalyzerContext : public DataDepVisitor class RequiresAnalyzerContext : public DataDepVisitor {
{
public: public:
RequiresAnalyzerContext() : requires_analyzer_context_(false) { } RequiresAnalyzerContext() : requires_analyzer_context_(false) {}
// Returns whether to continue traversal // Returns whether to continue traversal
bool PreProcess(DataDepElement* element) override; bool PreProcess(DataDepElement* element) override;
bool PostProcess(DataDepElement* element) override; bool PostProcess(DataDepElement* element) override;
bool requires_analyzer_context() const { return requires_analyzer_context_; } bool requires_analyzer_context() const { return requires_analyzer_context_; }
static bool compute(DataDepElement* element); static bool compute(DataDepElement* element);
protected: protected:
void ProcessExpr(Expr* expr); void ProcessExpr(Expr* expr);
bool requires_analyzer_context_; bool requires_analyzer_context_;
}; };
#endif // pac_datadep_h #endif // pac_datadep_h

View file

@ -5,56 +5,48 @@
#include "pac_output.h" #include "pac_output.h"
#include "pac_utils.h" #include "pac_utils.h"
DataPtr::DataPtr(Env* env, const ID* id, const int offset) : id_(id), offset_(offset) DataPtr::DataPtr(Env* env, const ID* id, const int offset) : id_(id), offset_(offset) {
{ if ( id_ ) {
if ( id_ ) if ( ! env->Evaluated(id_) )
{ throw ExceptionIDNotEvaluated(id_);
if ( ! env->Evaluated(id_) )
throw ExceptionIDNotEvaluated(id_);
if ( offset_ == 0 ) if ( offset_ == 0 )
ptr_expr_ = strfmt("%s", env->RValue(id_)); ptr_expr_ = strfmt("%s", env->RValue(id_));
else else
ptr_expr_ = strfmt("(%s + %d)", env->RValue(id_), offset_); ptr_expr_ = strfmt("(%s + %d)", env->RValue(id_), offset_);
} }
else else
ptr_expr_ = "(null id)"; ptr_expr_ = "(null id)";
} }
int DataPtr::AbsOffset(const ID* base_ptr) const int DataPtr::AbsOffset(const ID* base_ptr) const { return (id() == base_ptr) ? offset() : -1; }
{
return (id() == base_ptr) ? offset() : -1;
}
char* DataPtr::AbsOffsetExpr(Env* env, const ID* base_ptr) const char* DataPtr::AbsOffsetExpr(Env* env, const ID* base_ptr) const {
{ if ( AbsOffset(base_ptr) >= 0 )
if ( AbsOffset(base_ptr) >= 0 ) return nfmt("%d", offset());
return nfmt("%d", offset()); else
else return nfmt("(%s - %s)", ptr_expr(), env->RValue(base_ptr));
return nfmt("(%s - %s)", ptr_expr(), env->RValue(base_ptr)); }
}
void DataPtr::GenBoundaryCheck(Output* out_cc, Env* env, const char* data_size, void DataPtr::GenBoundaryCheck(Output* out_cc, Env* env, const char* data_size, const char* data_name) const {
const char* data_name) const ASSERT(id_);
{
ASSERT(id_);
out_cc->println("// Checking out-of-bound for \"%s\"", data_name); out_cc->println("// Checking out-of-bound for \"%s\"", data_name);
out_cc->println("if ( %s + (%s) > %s || %s + (%s) < %s )", ptr_expr(), data_size, out_cc->println("if ( %s + (%s) > %s || %s + (%s) < %s )", ptr_expr(), data_size, env->RValue(end_of_data),
env->RValue(end_of_data), ptr_expr(), data_size, ptr_expr()); ptr_expr(), data_size, ptr_expr());
out_cc->inc_indent(); out_cc->inc_indent();
out_cc->println("{"); out_cc->println("{");
char* data_offset = AbsOffsetExpr(env, begin_of_data); char* data_offset = AbsOffsetExpr(env, begin_of_data);
out_cc->println("// Handle out-of-bound condition"); out_cc->println("// Handle out-of-bound condition");
out_cc->println("throw binpac::ExceptionOutOfBound(\"%s\",", data_name); out_cc->println("throw binpac::ExceptionOutOfBound(\"%s\",", data_name);
out_cc->println(" (%s) + (%s), ", data_offset, data_size); out_cc->println(" (%s) + (%s), ", data_offset, data_size);
out_cc->println(" (%s) - (%s));", env->RValue(end_of_data), env->RValue(begin_of_data)); out_cc->println(" (%s) - (%s));", env->RValue(end_of_data), env->RValue(begin_of_data));
delete[] data_offset; delete[] data_offset;
out_cc->println("}"); out_cc->println("}");
out_cc->dec_indent(); out_cc->dec_indent();
} }

View file

@ -9,40 +9,36 @@
// A data pointer is represented by an data pointer variable // A data pointer is represented by an data pointer variable
// plus a constant offset. // plus a constant offset.
class DataPtr class DataPtr {
{
public: public:
DataPtr(Env* env, const ID* arg_id, const int arg_off); DataPtr(Env* env, const ID* arg_id, const int arg_off);
DataPtr(DataPtr const& x) { *this = x; } DataPtr(DataPtr const& x) { *this = x; }
DataPtr const& operator=(DataPtr const& x) DataPtr const& operator=(DataPtr const& x) {
{ id_ = x.id();
id_ = x.id(); offset_ = x.offset();
offset_ = x.offset(); ptr_expr_ = x.ptr_expr();
ptr_expr_ = x.ptr_expr();
return *this; return *this;
} }
const ID* id() const { return id_; } const ID* id() const { return id_; }
int offset() const { return offset_; } int offset() const { return offset_; }
const char* ptr_expr() const const char* ptr_expr() const {
{ ASSERT(id_);
ASSERT(id_); return ptr_expr_.c_str();
return ptr_expr_.c_str(); }
}
int AbsOffset(const ID* base_ptr) const; int AbsOffset(const ID* base_ptr) const;
char* AbsOffsetExpr(Env* env, const ID* base_ptr) const; char* AbsOffsetExpr(Env* env, const ID* base_ptr) const;
void GenBoundaryCheck(Output* out, Env* env, const char* data_size, void GenBoundaryCheck(Output* out, Env* env, const char* data_size, const char* data_name) const;
const char* data_name) const;
protected: protected:
const ID* id_; const ID* id_;
int offset_; int offset_;
string ptr_expr_; string ptr_expr_;
}; };
#endif // pac_dataptr_h #endif // pac_dataptr_h

View file

@ -5,41 +5,33 @@
#include "pac_paramtype.h" #include "pac_paramtype.h"
#include "pac_varfield.h" #include "pac_varfield.h"
AnalyzerDataUnit::AnalyzerDataUnit(DataUnitType type, ID* id, ExprList* type_params, AnalyzerDataUnit::AnalyzerDataUnit(DataUnitType type, ID* id, ExprList* type_params, ExprList* context_params)
ExprList* context_params) : AnalyzerElement(DATAUNIT), type_(type), id_(id), type_params_(type_params), context_params_(context_params) {
: AnalyzerElement(DATAUNIT), type_(type), id_(id), type_params_(type_params), data_type_ = new ParameterizedType(id_, type_params_);
context_params_(context_params) context_type_ =
{ new ParameterizedType(AnalyzerContextDecl::current_analyzer_context()->id()->clone(), context_params_);
data_type_ = new ParameterizedType(id_, type_params_);
context_type_ = new ParameterizedType(
AnalyzerContextDecl::current_analyzer_context()->id()->clone(), context_params_);
dataunit_var_field_ = new ParseVarField(Field::CLASS_MEMBER, dataunit_id->clone(), data_type()); dataunit_var_field_ = new ParseVarField(Field::CLASS_MEMBER, dataunit_id->clone(), data_type());
context_var_field_ = new PrivVarField(analyzer_context_id->clone(), context_type()); context_var_field_ = new PrivVarField(analyzer_context_id->clone(), context_type());
} }
AnalyzerDataUnit::~AnalyzerDataUnit() AnalyzerDataUnit::~AnalyzerDataUnit() {
{ delete dataunit_var_field_;
delete dataunit_var_field_; delete context_var_field_;
delete context_var_field_; }
}
void AnalyzerDataUnit::Prepare(Env* env) void AnalyzerDataUnit::Prepare(Env* env) {
{ dataunit_var_field_->Prepare(env);
dataunit_var_field_->Prepare(env); context_var_field_->Prepare(env);
context_var_field_->Prepare(env); }
}
void AnalyzerDataUnit::GenNewDataUnit(Output* out_cc, Env* env) void AnalyzerDataUnit::GenNewDataUnit(Output* out_cc, Env* env) {
{ out_cc->println("%s = new %s(%s);", env->LValue(dataunit_id), data_type()->class_name().c_str(),
out_cc->println("%s = new %s(%s);", env->LValue(dataunit_id), data_type()->class_name().c_str(), data_type()->EvalParameters(out_cc, env).c_str());
data_type()->EvalParameters(out_cc, env).c_str()); }
}
void AnalyzerDataUnit::GenNewContext(Output* out_cc, Env* env) void AnalyzerDataUnit::GenNewContext(Output* out_cc, Env* env) {
{ out_cc->println("%s = new %s(%s);", env->LValue(analyzer_context_id), context_type()->class_name().c_str(),
out_cc->println("%s = new %s(%s);", env->LValue(analyzer_context_id), context_type()->EvalParameters(out_cc, env).c_str());
context_type()->class_name().c_str(), env->SetEvaluated(analyzer_context_id);
context_type()->EvalParameters(out_cc, env).c_str()); }
env->SetEvaluated(analyzer_context_id);
}

View file

@ -6,44 +6,39 @@
// The type and parameters of input data unit of a flow. For instance, the // The type and parameters of input data unit of a flow. For instance, the
// data unit of a DCE/RPC flow is DCE_RPC_PDU. // data unit of a DCE/RPC flow is DCE_RPC_PDU.
class AnalyzerDataUnit : public AnalyzerElement class AnalyzerDataUnit : public AnalyzerElement {
{
public: public:
enum DataUnitType enum DataUnitType { DATAGRAM, FLOWUNIT };
{ AnalyzerDataUnit(DataUnitType type, ID* id, ExprList* type_params, ExprList* context_params);
DATAGRAM, ~AnalyzerDataUnit() override;
FLOWUNIT
};
AnalyzerDataUnit(DataUnitType type, ID* id, ExprList* type_params, ExprList* context_params);
~AnalyzerDataUnit() override;
void Prepare(Env* env); void Prepare(Env* env);
// Initializes dataunit_id // Initializes dataunit_id
void GenNewDataUnit(Output* out_cc, Env* env); void GenNewDataUnit(Output* out_cc, Env* env);
// Initializes analyzer_context_id // Initializes analyzer_context_id
void GenNewContext(Output* out_cc, Env* env); void GenNewContext(Output* out_cc, Env* env);
DataUnitType type() const { return type_; } DataUnitType type() const { return type_; }
const ID* id() const { return id_; } const ID* id() const { return id_; }
ExprList* type_params() const { return type_params_; } ExprList* type_params() const { return type_params_; }
ExprList* context_params() const { return context_params_; } ExprList* context_params() const { return context_params_; }
ParameterizedType* data_type() const { return data_type_; } ParameterizedType* data_type() const { return data_type_; }
ParameterizedType* context_type() const { return context_type_; } ParameterizedType* context_type() const { return context_type_; }
Field* dataunit_var_field() const { return dataunit_var_field_; } Field* dataunit_var_field() const { return dataunit_var_field_; }
Field* context_var_field() const { return context_var_field_; } Field* context_var_field() const { return context_var_field_; }
private: private:
DataUnitType type_; DataUnitType type_;
ID* id_; ID* id_;
ExprList* type_params_; ExprList* type_params_;
ExprList* context_params_; ExprList* context_params_;
ParameterizedType* data_type_; ParameterizedType* data_type_;
ParameterizedType* context_type_; ParameterizedType* context_type_;
Field* dataunit_var_field_; Field* dataunit_var_field_;
Field* context_var_field_; Field* context_var_field_;
}; };
#endif // pac_dataunit_h #endif // pac_dataunit_h

View file

@ -6,7 +6,9 @@
extern bool FLAGS_pac_debug; extern bool FLAGS_pac_debug;
#define ASSERT(x) assert(x) #define ASSERT(x) assert(x)
#define DEBUG_MSG(...) if ( FLAGS_pac_debug ) fprintf(stderr, __VA_ARGS__) #define DEBUG_MSG(...) \
if ( FLAGS_pac_debug ) \
fprintf(stderr, __VA_ARGS__)
#endif /* pac_dbg_h */ #endif /* pac_dbg_h */

View file

@ -17,140 +17,120 @@
DeclList* Decl::decl_list_ = nullptr; DeclList* Decl::decl_list_ = nullptr;
Decl::DeclMap Decl::decl_map_; Decl::DeclMap Decl::decl_map_;
Decl::Decl(ID* id, DeclType decl_type) : id_(id), decl_type_(decl_type), attrlist_(nullptr) Decl::Decl(ID* id, DeclType decl_type) : id_(id), decl_type_(decl_type), attrlist_(nullptr) {
{ decl_map_[id_] = this;
decl_map_[id_] = this; if ( ! decl_list_ )
if ( ! decl_list_ ) decl_list_ = new DeclList();
decl_list_ = new DeclList(); decl_list_->push_back(this);
decl_list_->push_back(this);
DEBUG_MSG("Finished Decl %s\n", id_->Name()); DEBUG_MSG("Finished Decl %s\n", id_->Name());
analyzer_context_ = nullptr; analyzer_context_ = nullptr;
} }
Decl::~Decl() Decl::~Decl() {
{ delete id_;
delete id_; delete_list(AttrList, attrlist_);
delete_list(AttrList, attrlist_); }
}
void Decl::AddAttrs(AttrList* attrs) void Decl::AddAttrs(AttrList* attrs) {
{ if ( ! attrs )
if ( ! attrs ) return;
return; if ( ! attrlist_ )
if ( ! attrlist_ ) attrlist_ = new AttrList();
attrlist_ = new AttrList(); foreach (i, AttrList, attrs) {
foreach (i, AttrList, attrs) attrlist_->push_back(*i);
{ ProcessAttr(*i);
attrlist_->push_back(*i); }
ProcessAttr(*i); }
}
}
void Decl::ProcessAttr(Attr* attr) void Decl::ProcessAttr(Attr* attr) { throw Exception(attr, "unhandled attribute"); }
{
throw Exception(attr, "unhandled attribute");
}
void Decl::SetAnalyzerContext() void Decl::SetAnalyzerContext() {
{ analyzer_context_ = AnalyzerContextDecl::current_analyzer_context();
analyzer_context_ = AnalyzerContextDecl::current_analyzer_context(); if ( ! analyzer_context_ ) {
if ( ! analyzer_context_ ) throw Exception(this, "analyzer context not defined");
{ }
throw Exception(this, "analyzer context not defined"); }
}
}
void Decl::ProcessDecls(Output* out_h, Output* out_cc) void Decl::ProcessDecls(Output* out_h, Output* out_cc) {
{ if ( ! decl_list_ )
if ( ! decl_list_ ) return;
return;
foreach (i, DeclList, decl_list_) foreach (i, DeclList, decl_list_) {
{ Decl* decl = *i;
Decl* decl = *i; current_decl_id = decl->id();
current_decl_id = decl->id(); decl->Prepare();
decl->Prepare(); }
}
foreach (i, DeclList, decl_list_) foreach (i, DeclList, decl_list_) {
{ Decl* decl = *i;
Decl* decl = *i; current_decl_id = decl->id();
current_decl_id = decl->id(); decl->GenExternDeclaration(out_h);
decl->GenExternDeclaration(out_h); }
}
out_h->println("namespace binpac {\n"); out_h->println("namespace binpac {\n");
out_cc->println("namespace binpac {\n"); out_cc->println("namespace binpac {\n");
AnalyzerContextDecl* analyzer_context = AnalyzerContextDecl::current_analyzer_context(); AnalyzerContextDecl* analyzer_context = AnalyzerContextDecl::current_analyzer_context();
foreach (i, DeclList, decl_list_) foreach (i, DeclList, decl_list_) {
{ Decl* decl = *i;
Decl* decl = *i; current_decl_id = decl->id();
current_decl_id = decl->id(); decl->GenForwardDeclaration(out_h);
decl->GenForwardDeclaration(out_h); }
}
if ( analyzer_context ) if ( analyzer_context )
analyzer_context->GenNamespaceEnd(out_h); analyzer_context->GenNamespaceEnd(out_h);
out_h->println(""); out_h->println("");
foreach (i, DeclList, decl_list_) foreach (i, DeclList, decl_list_) {
{ Decl* decl = *i;
Decl* decl = *i; current_decl_id = decl->id();
current_decl_id = decl->id(); decl->GenCode(out_h, out_cc);
decl->GenCode(out_h, out_cc); }
}
if ( analyzer_context ) if ( analyzer_context ) {
{ analyzer_context->GenNamespaceEnd(out_h);
analyzer_context->GenNamespaceEnd(out_h); analyzer_context->GenNamespaceEnd(out_cc);
analyzer_context->GenNamespaceEnd(out_cc); }
}
out_h->println("} // namespace binpac"); out_h->println("} // namespace binpac");
out_cc->println("} // namespace binpac"); out_cc->println("} // namespace binpac");
} }
Decl* Decl::LookUpDecl(const ID* id) Decl* Decl::LookUpDecl(const ID* id) {
{ DeclMap::iterator it = decl_map_.find(id);
DeclMap::iterator it = decl_map_.find(id); if ( it == decl_map_.end() )
if ( it == decl_map_.end() ) return nullptr;
return nullptr; return it->second;
return it->second; }
}
int HelperDecl::helper_id_seq = 0; int HelperDecl::helper_id_seq = 0;
HelperDecl::HelperDecl(HelperType helper_type, ID* context_id, EmbeddedCode* code) HelperDecl::HelperDecl(HelperType helper_type, ID* context_id, EmbeddedCode* code)
: Decl(new ID(strfmt("helper_%d", ++helper_id_seq)), HELPER), helper_type_(helper_type), : Decl(new ID(strfmt("helper_%d", ++helper_id_seq)), HELPER),
context_id_(context_id), code_(code) helper_type_(helper_type),
{ context_id_(context_id),
} code_(code) {}
HelperDecl::~HelperDecl() HelperDecl::~HelperDecl() {
{ delete context_id_;
delete context_id_; delete code_;
delete code_; }
}
void HelperDecl::Prepare() void HelperDecl::Prepare() {
{ // Do nothing
// Do nothing }
}
void HelperDecl::GenExternDeclaration(Output* out_h) void HelperDecl::GenExternDeclaration(Output* out_h) {
{ if ( helper_type_ == EXTERN )
if ( helper_type_ == EXTERN ) code_->GenCode(out_h, global_env());
code_->GenCode(out_h, global_env()); }
}
void HelperDecl::GenCode(Output* out_h, Output* out_cc) void HelperDecl::GenCode(Output* out_h, Output* out_cc) {
{ Env* env = global_env();
Env* env = global_env();
#if 0 #if 0
if ( context_id_ ) if ( context_id_ )
@ -172,12 +152,12 @@ void HelperDecl::GenCode(Output* out_h, Output* out_cc)
} }
#endif #endif
if ( helper_type_ == HEADER ) if ( helper_type_ == HEADER )
code_->GenCode(out_h, env); code_->GenCode(out_h, env);
else if ( helper_type_ == CODE ) else if ( helper_type_ == CODE )
code_->GenCode(out_cc, env); code_->GenCode(out_cc, env);
else if ( helper_type_ == EXTERN ) else if ( helper_type_ == EXTERN )
; // do nothing ; // do nothing
else else
ASSERT(0); ASSERT(0);
} }

View file

@ -4,93 +4,77 @@
#include "pac_common.h" #include "pac_common.h"
#include "pac_id.h" #include "pac_id.h"
class Decl : public Object class Decl : public Object {
{
public: public:
// Note: ANALYZER is not for AnalyzerDecl (which is an // Note: ANALYZER is not for AnalyzerDecl (which is an
// abstract class) , but for AnalyzerContextDecl. // abstract class) , but for AnalyzerContextDecl.
enum DeclType enum DeclType { ENUM, LET, TYPE, FUNC, CONN, FLOW, ANALYZER, HELPER, REGEX };
{
ENUM,
LET,
TYPE,
FUNC,
CONN,
FLOW,
ANALYZER,
HELPER,
REGEX
};
Decl(ID* id, DeclType decl_type); Decl(ID* id, DeclType decl_type);
virtual ~Decl(); virtual ~Decl();
const ID* id() const { return id_; } const ID* id() const { return id_; }
DeclType decl_type() const { return decl_type_; } DeclType decl_type() const { return decl_type_; }
AnalyzerContextDecl* analyzer_context() const { return analyzer_context_; } AnalyzerContextDecl* analyzer_context() const { return analyzer_context_; }
// NULL except for TypeDecl or AnalyzerDecl // NULL except for TypeDecl or AnalyzerDecl
virtual Env* env() const { return nullptr; } virtual Env* env() const { return nullptr; }
virtual void Prepare() = 0; virtual void Prepare() = 0;
// Generate declarations out of the "binpac" namespace // Generate declarations out of the "binpac" namespace
virtual void GenExternDeclaration(Output* out_h) virtual void GenExternDeclaration(Output* out_h) { /* do nothing */
{ /* do nothing */ }
}
// Generate declarations before definition of classes // Generate declarations before definition of classes
virtual void GenForwardDeclaration(Output* out_h) = 0; virtual void GenForwardDeclaration(Output* out_h) = 0;
virtual void GenCode(Output* out_h, Output* out_cc) = 0; virtual void GenCode(Output* out_h, Output* out_cc) = 0;
void TakeExprList(); void TakeExprList();
void AddAttrs(AttrList* attrlist); void AddAttrs(AttrList* attrlist);
void SetAnalyzerContext(); void SetAnalyzerContext();
protected: protected:
virtual void ProcessAttr(Attr* a); virtual void ProcessAttr(Attr* a);
ID* id_; ID* id_;
DeclType decl_type_; DeclType decl_type_;
AttrList* attrlist_; AttrList* attrlist_;
AnalyzerContextDecl* analyzer_context_; AnalyzerContextDecl* analyzer_context_;
public: public:
static void ProcessDecls(Output* out_h, Output* out_cc); static void ProcessDecls(Output* out_h, Output* out_cc);
static Decl* LookUpDecl(const ID* id); static Decl* LookUpDecl(const ID* id);
private: private:
static DeclList* decl_list_; static DeclList* decl_list_;
typedef map<const ID*, Decl*, ID_ptr_cmp> DeclMap; typedef map<const ID*, Decl*, ID_ptr_cmp> DeclMap;
static DeclMap decl_map_; static DeclMap decl_map_;
}; };
class HelperDecl : public Decl class HelperDecl : public Decl {
{
public: public:
enum HelperType enum HelperType {
{ HEADER,
HEADER, CODE,
CODE, EXTERN,
EXTERN, };
}; HelperDecl(HelperType type, ID* context_id, EmbeddedCode* code);
HelperDecl(HelperType type, ID* context_id, EmbeddedCode* code); ~HelperDecl() override;
~HelperDecl() override;
void Prepare() override; void Prepare() override;
void GenExternDeclaration(Output* out_h) override; void GenExternDeclaration(Output* out_h) override;
void GenForwardDeclaration(Output* out_h) override void GenForwardDeclaration(Output* out_h) override { /* do nothing */
{ /* do nothing */ }
} void GenCode(Output* out_h, Output* out_cc) override;
void GenCode(Output* out_h, Output* out_cc) override;
private: private:
HelperType helper_type_; HelperType helper_type_;
ID* context_id_; ID* context_id_;
EmbeddedCode* code_; EmbeddedCode* code_;
static int helper_id_seq; static int helper_id_seq;
}; };
#endif // pac_decl_h #endif // pac_decl_h

View file

@ -4,74 +4,52 @@
#include "pac_output.h" #include "pac_output.h"
#include "pac_primitive.h" #include "pac_primitive.h"
EmbeddedCodeSegment::EmbeddedCodeSegment(const string& s) : s_(s), primitive_(nullptr) { } EmbeddedCodeSegment::EmbeddedCodeSegment(const string& s) : s_(s), primitive_(nullptr) {}
EmbeddedCodeSegment::EmbeddedCodeSegment(PacPrimitive* primitive) EmbeddedCodeSegment::EmbeddedCodeSegment(PacPrimitive* primitive) : s_(""), primitive_(primitive) {}
: s_(""), primitive_(primitive) { }
EmbeddedCodeSegment::~EmbeddedCodeSegment() EmbeddedCodeSegment::~EmbeddedCodeSegment() { delete primitive_; }
{
delete primitive_;
}
string EmbeddedCodeSegment::ToCode(Env* env) string EmbeddedCodeSegment::ToCode(Env* env) {
{ if ( primitive_ && s_.empty() )
if ( primitive_ && s_.empty() ) s_ = primitive_->ToCode(env);
s_ = primitive_->ToCode(env); return s_;
return s_; }
}
EmbeddedCode::EmbeddedCode() EmbeddedCode::EmbeddedCode() { segments_ = new EmbeddedCodeSegmentList(); }
{
segments_ = new EmbeddedCodeSegmentList();
}
EmbeddedCode::~EmbeddedCode() EmbeddedCode::~EmbeddedCode() { delete_list(EmbeddedCodeSegmentList, segments_); }
{
delete_list(EmbeddedCodeSegmentList, segments_);
}
void EmbeddedCode::Append(int atom) void EmbeddedCode::Append(int atom) { current_segment_ += static_cast<char>(atom); }
{
current_segment_ += static_cast<char>(atom);
}
void EmbeddedCode::Append(const char* str) void EmbeddedCode::Append(const char* str) { current_segment_ += str; }
{
current_segment_ += str;
}
void EmbeddedCode::Append(PacPrimitive* primitive) void EmbeddedCode::Append(PacPrimitive* primitive) {
{ if ( ! current_segment_.empty() ) {
if ( ! current_segment_.empty() ) segments_->push_back(new EmbeddedCodeSegment(current_segment_));
{ current_segment_ = "";
segments_->push_back(new EmbeddedCodeSegment(current_segment_)); }
current_segment_ = ""; segments_->push_back(new EmbeddedCodeSegment(primitive));
} }
segments_->push_back(new EmbeddedCodeSegment(primitive));
}
void EmbeddedCode::GenCode(Output* out, Env* env) void EmbeddedCode::GenCode(Output* out, Env* env) {
{ if ( ! current_segment_.empty() ) {
if ( ! current_segment_.empty() ) segments_->push_back(new EmbeddedCodeSegment(current_segment_));
{ current_segment_ = "";
segments_->push_back(new EmbeddedCodeSegment(current_segment_)); }
current_segment_ = "";
}
// TODO: return to the generated file after embedded code // TODO: return to the generated file after embedded code
// out->print("#line %d \"%s\"\n", line_num, filename.c_str()); // out->print("#line %d \"%s\"\n", line_num, filename.c_str());
// Allow use of RValue for undefined ID, in which case the // Allow use of RValue for undefined ID, in which case the
// ID's name is used as its RValue // ID's name is used as its RValue
env->set_allow_undefined_id(true); env->set_allow_undefined_id(true);
foreach (i, EmbeddedCodeSegmentList, segments_) foreach (i, EmbeddedCodeSegmentList, segments_) {
{ EmbeddedCodeSegment* segment = *i;
EmbeddedCodeSegment* segment = *i; out->print("%s", segment->ToCode(env).c_str());
out->print("%s", segment->ToCode(env).c_str()); }
}
env->set_allow_undefined_id(false); env->set_allow_undefined_id(false);
out->print("\n"); out->print("\n");
} }

View file

@ -3,40 +3,38 @@
#include "pac_common.h" #include "pac_common.h"
class EmbeddedCodeSegment class EmbeddedCodeSegment {
{
public: public:
explicit EmbeddedCodeSegment(const string& s); explicit EmbeddedCodeSegment(const string& s);
explicit EmbeddedCodeSegment(PacPrimitive* primitive); explicit EmbeddedCodeSegment(PacPrimitive* primitive);
~EmbeddedCodeSegment(); ~EmbeddedCodeSegment();
string ToCode(Env* env); string ToCode(Env* env);
private: private:
string s_; string s_;
PacPrimitive* primitive_; PacPrimitive* primitive_;
}; };
typedef vector<EmbeddedCodeSegment*> EmbeddedCodeSegmentList; typedef vector<EmbeddedCodeSegment*> EmbeddedCodeSegmentList;
class EmbeddedCode : public Object class EmbeddedCode : public Object {
{
public: public:
EmbeddedCode(); EmbeddedCode();
~EmbeddedCode(); ~EmbeddedCode();
// Append a character // Append a character
void Append(int atom); void Append(int atom);
void Append(const char* str); void Append(const char* str);
// Append a PAC primitive // Append a PAC primitive
void Append(PacPrimitive* primitive); void Append(PacPrimitive* primitive);
void GenCode(Output* out, Env* env); void GenCode(Output* out, Env* env);
private: private:
string current_segment_; string current_segment_;
EmbeddedCodeSegmentList* segments_; EmbeddedCodeSegmentList* segments_;
}; };
#endif // pac_embedded_h #endif // pac_embedded_h

View file

@ -6,61 +6,52 @@
#include "pac_output.h" #include "pac_output.h"
#include "pac_typedecl.h" #include "pac_typedecl.h"
Enum::Enum(ID* id, Expr* expr) : id_(id), expr_(expr) { } Enum::Enum(ID* id, Expr* expr) : id_(id), expr_(expr) {}
Enum::~Enum() Enum::~Enum() {
{ delete id_;
delete id_; delete expr_;
delete expr_; }
}
void Enum::GenHeader(Output* out_h, int* pval) void Enum::GenHeader(Output* out_h, int* pval) {
{ ASSERT(pval);
ASSERT(pval); if ( expr_ ) {
if ( expr_ ) if ( ! expr_->ConstFold(global_env(), pval) )
{ throw ExceptionNonConstExpr(expr_);
if ( ! expr_->ConstFold(global_env(), pval) ) out_h->println("%s = %d,", id_->Name(), *pval);
throw ExceptionNonConstExpr(expr_); }
out_h->println("%s = %d,", id_->Name(), *pval); else
} out_h->println("%s,", id_->Name());
else global_env()->AddConstID(id_, *pval);
out_h->println("%s,", id_->Name()); }
global_env()->AddConstID(id_, *pval);
}
EnumDecl::EnumDecl(ID* id, EnumList* enumlist) : Decl(id, ENUM), enumlist_(enumlist) EnumDecl::EnumDecl(ID* id, EnumList* enumlist) : Decl(id, ENUM), enumlist_(enumlist) {
{ ID* type_id = id->clone();
ID* type_id = id->clone(); datatype_ = new ExternType(type_id, ExternType::NUMBER);
datatype_ = new ExternType(type_id, ExternType::NUMBER); extern_typedecl_ = new TypeDecl(type_id, nullptr, datatype_);
extern_typedecl_ = new TypeDecl(type_id, nullptr, datatype_); }
}
EnumDecl::~EnumDecl() EnumDecl::~EnumDecl() {
{ delete_list(EnumList, enumlist_);
delete_list(EnumList, enumlist_); delete extern_typedecl_;
delete extern_typedecl_; }
}
void EnumDecl::Prepare() void EnumDecl::Prepare() {
{ // Do nothing
// Do nothing }
}
void EnumDecl::GenForwardDeclaration(Output* out_h) void EnumDecl::GenForwardDeclaration(Output* out_h) {
{ out_h->println("enum %s {", id_->Name());
out_h->println("enum %s {", id_->Name()); out_h->inc_indent();
out_h->inc_indent(); int c = 0;
int c = 0; foreach (i, EnumList, enumlist_) {
foreach (i, EnumList, enumlist_) (*i)->GenHeader(out_h, &c);
{ ++c;
(*i)->GenHeader(out_h, &c); }
++c; out_h->dec_indent();
} out_h->println("};");
out_h->dec_indent(); }
out_h->println("};");
}
void EnumDecl::GenCode(Output* out_h, Output* /* out_cc */) void EnumDecl::GenCode(Output* out_h, Output* /* out_cc */) {
{ // Do nothing
// Do nothing }
}

View file

@ -3,35 +3,33 @@
#include "pac_decl.h" #include "pac_decl.h"
class Enum class Enum {
{
public: public:
Enum(ID* id, Expr* expr = 0); Enum(ID* id, Expr* expr = 0);
~Enum(); ~Enum();
void GenHeader(Output* out_h, int* pval); void GenHeader(Output* out_h, int* pval);
private: private:
ID* id_; ID* id_;
Expr* expr_; Expr* expr_;
}; };
class EnumDecl : public Decl class EnumDecl : public Decl {
{
public: public:
EnumDecl(ID* id, EnumList* enumlist); EnumDecl(ID* id, EnumList* enumlist);
~EnumDecl() override; ~EnumDecl() override;
Type* DataType() const { return datatype_; } Type* DataType() const { return datatype_; }
void Prepare() override; void Prepare() override;
void GenForwardDeclaration(Output* out_h) override; void GenForwardDeclaration(Output* out_h) override;
void GenCode(Output* out_h, Output* out_cc) override; void GenCode(Output* out_h, Output* out_cc) override;
private: private:
EnumList* enumlist_; EnumList* enumlist_;
Type* datatype_; Type* datatype_;
TypeDecl* extern_typedecl_; TypeDecl* extern_typedecl_;
}; };
#endif // pac_enum_h #endif // pac_enum_h

View file

@ -4,75 +4,58 @@
#include "pac_id.h" #include "pac_id.h"
#include "pac_utils.h" #include "pac_utils.h"
Exception::Exception(const Object* o, string msg) Exception::Exception(const Object* o, string msg) {
{ if ( o ) {
if ( o ) msg_ = o->Location();
{ msg_ += ": error : ";
msg_ = o->Location(); }
msg_ += ": error : ";
}
msg_ += msg; msg_ += msg;
if ( FLAGS_pac_debug ) if ( FLAGS_pac_debug ) {
{ DEBUG_MSG("Exception: %s\n", msg_.c_str());
DEBUG_MSG("Exception: %s\n", msg_.c_str()); abort();
abort(); }
} }
}
ExceptionIDNotFound::ExceptionIDNotFound(const ID* id) : Exception(id), id_(id) ExceptionIDNotFound::ExceptionIDNotFound(const ID* id) : Exception(id), id_(id) {
{ append(strfmt("`%s' undeclared", id_->Name()));
append(strfmt("`%s' undeclared", id_->Name())); }
}
ExceptionIDRedefinition::ExceptionIDRedefinition(const ID* id) : Exception(id), id_(id) ExceptionIDRedefinition::ExceptionIDRedefinition(const ID* id) : Exception(id), id_(id) {
{ append(strfmt("`%s' redefined", id_->Name()));
append(strfmt("`%s' redefined", id_->Name())); }
}
ExceptionIDNotEvaluated::ExceptionIDNotEvaluated(const ID* id) : Exception(id), id_(id) ExceptionIDNotEvaluated::ExceptionIDNotEvaluated(const ID* id) : Exception(id), id_(id) {
{ append(strfmt("ID `%s' not evaluated before used", id->Name()));
append(strfmt("ID `%s' not evaluated before used", id->Name())); }
}
ExceptionIDNotField::ExceptionIDNotField(const ID* id) : Exception(id), id_(id) ExceptionIDNotField::ExceptionIDNotField(const ID* id) : Exception(id), id_(id) {
{ append(strfmt("ID `%s' is not a field", id_->Name()));
append(strfmt("ID `%s' is not a field", id_->Name())); }
}
ExceptionMemberNotFound::ExceptionMemberNotFound(const ID* type_id, const ID* member_id) ExceptionMemberNotFound::ExceptionMemberNotFound(const ID* type_id, const ID* member_id)
: Exception(member_id), type_id_(type_id), member_id_(member_id) : Exception(member_id), type_id_(type_id), member_id_(member_id) {
{ append(strfmt("type %s does not have member `%s'", type_id_->Name(), member_id_->Name()));
append(strfmt("type %s does not have member `%s'", type_id_->Name(), member_id_->Name())); }
}
ExceptionCyclicDependence::ExceptionCyclicDependence(const ID* id) : Exception(id), id_(id) ExceptionCyclicDependence::ExceptionCyclicDependence(const ID* id) : Exception(id), id_(id) {
{ append(strfmt("cyclic dependence through `%s'", id_->Name()));
append(strfmt("cyclic dependence through `%s'", id_->Name())); }
}
ExceptionPaddingError::ExceptionPaddingError(const Object* o, string msg) : Exception(o) ExceptionPaddingError::ExceptionPaddingError(const Object* o, string msg) : Exception(o) { append(msg.c_str()); }
{
append(msg.c_str());
}
ExceptionNonConstExpr::ExceptionNonConstExpr(const Expr* expr) : Exception(expr), expr(expr) ExceptionNonConstExpr::ExceptionNonConstExpr(const Expr* expr) : Exception(expr), expr(expr) {
{ append(strfmt("Expression `%s' is not constant", expr->orig()));
append(strfmt("Expression `%s' is not constant", expr->orig())); }
}
ExceptionInvalidCaseSizeExpr::ExceptionInvalidCaseSizeExpr(const Expr* expr) ExceptionInvalidCaseSizeExpr::ExceptionInvalidCaseSizeExpr(const Expr* expr) : Exception(expr), expr(expr) {
: Exception(expr), expr(expr) append(strfmt("Expression `%s' is greater than the 32-bit limit for use as a case index", expr->orig()));
{ }
append(strfmt("Expression `%s' is greater than the 32-bit limit for use as a case index",
expr->orig()));
}
ExceptionInvalidCaseLimitExpr::ExceptionInvalidCaseLimitExpr(const Expr* expr) ExceptionInvalidCaseLimitExpr::ExceptionInvalidCaseLimitExpr(const Expr* expr) : Exception(expr), expr(expr) {
: Exception(expr), expr(expr) append(
{ strfmt("Expression `%s' as a case index is outside the numeric limit of the type used "
append(strfmt("Expression `%s' as a case index is outside the numeric limit of the type used " "for the switch expression",
"for the switch expression", expr->orig()));
expr->orig())); }
}

View file

@ -6,108 +6,97 @@ using namespace std;
#include "pac_common.h" #include "pac_common.h"
class Exception class Exception {
{
public: public:
Exception(const Object* o, string msg = ""); Exception(const Object* o, string msg = "");
const char* msg() const { return msg_.c_str(); } const char* msg() const { return msg_.c_str(); }
void append(string s) { msg_ += s; } void append(string s) { msg_ += s; }
private: private:
string msg_; string msg_;
}; };
class ExceptionIDNotFound : public Exception class ExceptionIDNotFound : public Exception {
{
public: public:
ExceptionIDNotFound(const ID* id); ExceptionIDNotFound(const ID* id);
const ID* id() const { return id_; } const ID* id() const { return id_; }
private: private:
const ID* id_; const ID* id_;
}; };
class ExceptionIDRedefinition : public Exception class ExceptionIDRedefinition : public Exception {
{
public: public:
ExceptionIDRedefinition(const ID* id); ExceptionIDRedefinition(const ID* id);
const ID* id() const { return id_; } const ID* id() const { return id_; }
private: private:
const ID* id_; const ID* id_;
}; };
class ExceptionIDNotEvaluated : public Exception class ExceptionIDNotEvaluated : public Exception {
{
public: public:
ExceptionIDNotEvaluated(const ID* id); ExceptionIDNotEvaluated(const ID* id);
const ID* id() const { return id_; } const ID* id() const { return id_; }
private: private:
const ID* id_; const ID* id_;
}; };
class ExceptionCyclicDependence : public Exception class ExceptionCyclicDependence : public Exception {
{
public: public:
ExceptionCyclicDependence(const ID* id); ExceptionCyclicDependence(const ID* id);
const ID* id() const { return id_; } const ID* id() const { return id_; }
private: private:
const ID* id_; const ID* id_;
}; };
class ExceptionPaddingError : public Exception class ExceptionPaddingError : public Exception {
{
public: public:
ExceptionPaddingError(const Object* o, string msg); ExceptionPaddingError(const Object* o, string msg);
}; };
class ExceptionIDNotField : public Exception class ExceptionIDNotField : public Exception {
{
public: public:
ExceptionIDNotField(const ID* id); ExceptionIDNotField(const ID* id);
const ID* id() const { return id_; } const ID* id() const { return id_; }
private: private:
const ID* id_; const ID* id_;
}; };
class ExceptionMemberNotFound : public Exception class ExceptionMemberNotFound : public Exception {
{
public: public:
ExceptionMemberNotFound(const ID* type_id, const ID* member_id); ExceptionMemberNotFound(const ID* type_id, const ID* member_id);
private: private:
const ID *type_id_, *member_id_; const ID *type_id_, *member_id_;
}; };
class ExceptionNonConstExpr : public Exception class ExceptionNonConstExpr : public Exception {
{
public: public:
ExceptionNonConstExpr(const Expr* expr); ExceptionNonConstExpr(const Expr* expr);
private: private:
const Expr* expr; const Expr* expr;
}; };
class ExceptionInvalidCaseSizeExpr : public Exception class ExceptionInvalidCaseSizeExpr : public Exception {
{
public: public:
ExceptionInvalidCaseSizeExpr(const Expr* expr); ExceptionInvalidCaseSizeExpr(const Expr* expr);
private: private:
const Expr* expr; const Expr* expr;
}; };
class ExceptionInvalidCaseLimitExpr : public Exception class ExceptionInvalidCaseLimitExpr : public Exception {
{
public: public:
ExceptionInvalidCaseLimitExpr(const Expr* expr); ExceptionInvalidCaseLimitExpr(const Expr* expr);
private: private:
const Expr* expr; const Expr* expr;
}; };
#endif /* pac_exception_h */ #endif /* pac_exception_h */

File diff suppressed because it is too large Load diff

View file

@ -6,135 +6,132 @@
class CaseExpr; class CaseExpr;
class Expr : public Object, public DataDepElement class Expr : public Object, public DataDepElement {
{
public: public:
enum ExprType enum ExprType {
{
#define EXPR_DEF(type, x, y) type, #define EXPR_DEF(type, x, y) type,
#include "pac_expr.def" #include "pac_expr.def"
#undef EXPR_DEF #undef EXPR_DEF
}; };
void init(); void init();
Expr(ID* id); Expr(ID* id);
Expr(Number* num); Expr(Number* num);
Expr(ConstString* s); Expr(ConstString* s);
Expr(RegEx* regex); Expr(RegEx* regex);
Expr(ExprList* args); // for EXPR_CALLARGS Expr(ExprList* args); // for EXPR_CALLARGS
Expr(Expr* index, CaseExprList* cases); Expr(Expr* index, CaseExprList* cases);
Expr(ExprType type, Expr* op1); Expr(ExprType type, Expr* op1);
Expr(ExprType type, Expr* op1, Expr* op2); Expr(ExprType type, Expr* op1, Expr* op2);
Expr(ExprType type, Expr* op1, Expr* op2, Expr* op3); Expr(ExprType type, Expr* op1, Expr* op2, Expr* op3);
~Expr() override; ~Expr() override;
const char* orig() const { return orig_.c_str(); } const char* orig() const { return orig_.c_str(); }
const ID* id() const { return id_; } const ID* id() const { return id_; }
const char* str() const { return str_.c_str(); } const char* str() const { return str_.c_str(); }
ExprType expr_type() const { return expr_type_; } ExprType expr_type() const { return expr_type_; }
void AddCaseExpr(CaseExpr* case_expr); void AddCaseExpr(CaseExpr* case_expr);
// Returns the data "type" of the expression. Here we only // Returns the data "type" of the expression. Here we only
// do a serious job for the EXPR_MEMBER and EXPR_SUBSCRIPT // do a serious job for the EXPR_MEMBER and EXPR_SUBSCRIPT
// operators. For arithmetic operations, we fall back // operators. For arithmetic operations, we fall back
// to "int". // to "int".
Type* DataType(Env* env) const; Type* DataType(Env* env) const;
string DataTypeStr(Env* env) const; string DataTypeStr(Env* env) const;
// Note: EvalExpr() may generate C++ statements in order to evaluate // Note: EvalExpr() may generate C++ statements in order to evaluate
// variables in the expression, so the following is wrong: // variables in the expression, so the following is wrong:
// //
// out->print("int x = "); // out->print("int x = ");
// out->println("%s", expr->EvalExpr(out, env)); // out->println("%s", expr->EvalExpr(out, env));
// //
// While putting them together is right: // While putting them together is right:
// //
// out->println("int x = %s", expr->EvalExpr(out, env)); // out->println("int x = %s", expr->EvalExpr(out, env));
// //
const char* EvalExpr(Output* out, Env* env); const char* EvalExpr(Output* out, Env* env);
// force evaulation of IDs contained in this expression; // force evaulation of IDs contained in this expression;
// necessary with case expr and conditional let fields (&if) // necessary with case expr and conditional let fields (&if)
// for correct parsing of fields // for correct parsing of fields
void ForceIDEval(Output* out_cc, Env* env); void ForceIDEval(Output* out_cc, Env* env);
// Returns the set_* function of the expression. // Returns the set_* function of the expression.
// The expression must be of form ID or x.ID. // The expression must be of form ID or x.ID.
string SetFunc(Output* out, Env* env); string SetFunc(Output* out, Env* env);
// Returns true if the expression folds to an integer // Returns true if the expression folds to an integer
// constant with env, and puts the constant in *pn. // constant with env, and puts the constant in *pn.
// //
bool ConstFold(Env* env, int* pn) const; bool ConstFold(Env* env, int* pn) const;
// Whether id is referenced in the expression // Whether id is referenced in the expression
bool HasReference(const ID* id) const; bool HasReference(const ID* id) const;
// Suppose the data for type might be incomplete, what is // Suppose the data for type might be incomplete, what is
// the minimal number of bytes from data head required to // the minimal number of bytes from data head required to
// compute the expression? For example, how many bytes of frame // compute the expression? For example, how many bytes of frame
// header do we need to determine the length of the frame? // header do we need to determine the length of the frame?
// //
// The parameter <env> points to the Env of a type. // The parameter <env> points to the Env of a type.
// //
// Returns -1 if the number is not a constant. // Returns -1 if the number is not a constant.
// //
int MinimalHeaderSize(Env* env); int MinimalHeaderSize(Env* env);
// Whether evaluation of the expression requires the analyzer context // Whether evaluation of the expression requires the analyzer context
bool RequiresAnalyzerContext() const; bool RequiresAnalyzerContext() const;
protected: protected:
bool DoTraverse(DataDepVisitor* visitor) override; bool DoTraverse(DataDepVisitor* visitor) override;
private: private:
ExprType expr_type_; ExprType expr_type_;
int num_operands_; int num_operands_;
Expr* operand_[3]; Expr* operand_[3];
ID* id_; // EXPR_ID ID* id_; // EXPR_ID
Number* num_; // EXPR_NUM Number* num_; // EXPR_NUM
ConstString* cstr_; // EXPR_CSTR ConstString* cstr_; // EXPR_CSTR
RegEx* regex_; // EXPR_REGEX RegEx* regex_; // EXPR_REGEX
ExprList* args_; // EXPR_CALLARGS ExprList* args_; // EXPR_CALLARGS
CaseExprList* cases_; // EXPR_CASE CaseExprList* cases_; // EXPR_CASE
string str_; // value string string str_; // value string
string orig_; // original string for debugging info string orig_; // original string for debugging info
void GenStrFromFormat(Env* env); void GenStrFromFormat(Env* env);
void GenEval(Output* out, Env* env); void GenEval(Output* out, Env* env);
void GenCaseEval(Output* out_cc, Env* env); void GenCaseEval(Output* out_cc, Env* env);
}; };
string OrigExprList(ExprList* exprlist); string OrigExprList(ExprList* exprlist);
string EvalExprList(ExprList* exprlist, Output* out, Env* env); string EvalExprList(ExprList* exprlist, Output* out, Env* env);
// An entry of the case expression, consisting of one or more constant // An entry of the case expression, consisting of one or more constant
// expressions for the case index and a value expression. // expressions for the case index and a value expression.
class CaseExpr : public Object, public DataDepElement class CaseExpr : public Object, public DataDepElement {
{
public: public:
CaseExpr(ExprList* index, Expr* value); CaseExpr(ExprList* index, Expr* value);
~CaseExpr() override; ~CaseExpr() override;
ExprList* index() const { return index_; } ExprList* index() const { return index_; }
Expr* value() const { return value_; } Expr* value() const { return value_; }
bool HasReference(const ID* id) const; bool HasReference(const ID* id) const;
bool RequiresAnalyzerContext() const; bool RequiresAnalyzerContext() const;
protected: protected:
bool DoTraverse(DataDepVisitor* visitor) override; bool DoTraverse(DataDepVisitor* visitor) override;
private: private:
ExprList* index_; ExprList* index_;
Expr* value_; Expr* value_;
}; };
#endif // pac_expr_h #endif // pac_expr_h

View file

@ -4,66 +4,42 @@
#include "pac_id.h" #include "pac_id.h"
#include "pac_output.h" #include "pac_output.h"
bool ExternType::DefineValueVar() const bool ExternType::DefineValueVar() const { return true; }
{
return true;
}
string ExternType::DataTypeStr() const string ExternType::DataTypeStr() const {
{ switch ( ext_type_ ) {
switch ( ext_type_ ) case PLAIN:
{ case NUMBER: return id_->Name();
case PLAIN: case POINTER: return string(id_->Name()) + " *";
case NUMBER: default: ASSERT(0); return "";
return id_->Name(); }
case POINTER: }
return string(id_->Name()) + " *";
default:
ASSERT(0);
return "";
}
}
int ExternType::StaticSize(Env* env) const int ExternType::StaticSize(Env* env) const {
{ ASSERT(0);
ASSERT(0); return -1;
return -1; }
}
bool ExternType::ByteOrderSensitive() const bool ExternType::ByteOrderSensitive() const { return false; }
{
return false;
}
string ExternType::EvalMember(const ID* member_id) const string ExternType::EvalMember(const ID* member_id) const {
{ return strfmt("%s%s", ext_type_ == POINTER ? "->" : ".", member_id->Name());
return strfmt("%s%s", ext_type_ == POINTER ? "->" : ".", member_id->Name()); }
}
void ExternType::GenInitCode(Output* out_cc, Env* env) void ExternType::GenInitCode(Output* out_cc, Env* env) {
{ if ( IsNumericType() )
if ( IsNumericType() ) out_cc->println("%s = 0;", env->LValue(value_var()));
out_cc->println("%s = 0;", env->LValue(value_var())); else if ( IsPointerType() )
else if ( IsPointerType() ) out_cc->println("%s = nullptr;", env->LValue(value_var()));
out_cc->println("%s = nullptr;", env->LValue(value_var()));
Type::GenInitCode(out_cc, env); Type::GenInitCode(out_cc, env);
} }
void ExternType::DoGenParseCode(Output* out, Env* env, const DataPtr& data, int flags) void ExternType::DoGenParseCode(Output* out, Env* env, const DataPtr& data, int flags) { ASSERT(0); }
{
ASSERT(0);
}
void ExternType::GenDynamicSize(Output* out, Env* env, const DataPtr& data) void ExternType::GenDynamicSize(Output* out, Env* env, const DataPtr& data) { ASSERT(0); }
{
ASSERT(0);
}
Type* ExternType::DoClone() const Type* ExternType::DoClone() const { return new ExternType(id_->clone(), ext_type_); }
{
return new ExternType(id_->clone(), ext_type_);
}
// Definitions of pre-defined external types // Definitions of pre-defined external types
@ -71,16 +47,15 @@ Type* ExternType::DoClone() const
#include "pac_externtype.def" #include "pac_externtype.def"
#undef EXTERNTYPE #undef EXTERNTYPE
void ExternType::static_init() void ExternType::static_init() {
{ ID* id;
ID* id; // TypeDecl *decl;
// TypeDecl *decl; // decl = new TypeDecl(id, 0, extern_type_##name);
// decl = new TypeDecl(id, 0, extern_type_##name);
#define EXTERNTYPE(name, ctype, exttype) \ #define EXTERNTYPE(name, ctype, exttype) \
id = new ID(#ctype); \ id = new ID(#ctype); \
extern_type_##name = new ExternType(id, ExternType::exttype); \ extern_type_##name = new ExternType(id, ExternType::exttype); \
Type::AddPredefinedType(#name, extern_type_##name); Type::AddPredefinedType(#name, extern_type_##name);
#include "pac_externtype.def" #include "pac_externtype.def"
#undef EXTERNTYPE #undef EXTERNTYPE
} }

View file

@ -8,41 +8,35 @@
// spefication, e.g., in a record field). The type name is copied // spefication, e.g., in a record field). The type name is copied
// literally to the compiled code. // literally to the compiled code.
class ExternType : public Type class ExternType : public Type {
{
public: public:
enum EXTType enum EXTType { PLAIN, NUMBER, POINTER };
{ ExternType(const ID* id, EXTType ext_type) : Type(EXTERN), id_(id), ext_type_(ext_type) {}
PLAIN,
NUMBER,
POINTER
};
ExternType(const ID* id, EXTType ext_type) : Type(EXTERN), id_(id), ext_type_(ext_type) { }
bool DefineValueVar() const override; bool DefineValueVar() const override;
string DataTypeStr() const override; string DataTypeStr() const override;
int StaticSize(Env* env) const override; int StaticSize(Env* env) const override;
bool ByteOrderSensitive() const override; bool ByteOrderSensitive() const override;
string EvalMember(const ID* member_id) const override; string EvalMember(const ID* member_id) const override;
bool IsNumericType() const override { return ext_type_ == NUMBER; } bool IsNumericType() const override { return ext_type_ == NUMBER; }
bool IsPointerType() const override { return ext_type_ == POINTER; } bool IsPointerType() const override { return ext_type_ == POINTER; }
void GenInitCode(Output* out_cc, Env* env) override; void GenInitCode(Output* out_cc, Env* env) override;
protected: protected:
void DoGenParseCode(Output* out, Env* env, const DataPtr& data, int flags) override; void DoGenParseCode(Output* out, Env* env, const DataPtr& data, int flags) override;
void GenDynamicSize(Output* out, Env* env, const DataPtr& data) override; void GenDynamicSize(Output* out, Env* env, const DataPtr& data) override;
Type* DoClone() const override; Type* DoClone() const override;
private: private:
const ID* id_; const ID* id_;
EXTType ext_type_; EXTType ext_type_;
public: public:
static void static_init(); static void static_init();
}; };
#define EXTERNTYPE(name, ctype, exttype) extern ExternType* extern_type_##name; #define EXTERNTYPE(name, ctype, exttype) extern ExternType* extern_type_##name;
#include "pac_externtype.def" #include "pac_externtype.def"

View file

@ -7,138 +7,117 @@
#include "pac_type.h" #include "pac_type.h"
Field::Field(FieldType tof, int flags, ID* id, Type* type) Field::Field(FieldType tof, int flags, ID* id, Type* type)
: DataDepElement(DataDepElement::FIELD), tof_(tof), flags_(flags), id_(id), type_(type) : DataDepElement(DataDepElement::FIELD), tof_(tof), flags_(flags), id_(id), type_(type) {
{ decl_id_ = current_decl_id;
decl_id_ = current_decl_id; field_id_str_ = strfmt("%s:%s", decl_id()->Name(), id_->Name());
field_id_str_ = strfmt("%s:%s", decl_id()->Name(), id_->Name()); attrs_ = nullptr;
attrs_ = nullptr; }
}
Field::~Field() Field::~Field() {
{ delete id_;
delete id_; delete type_;
delete type_; delete_list(AttrList, attrs_);
delete_list(AttrList, attrs_); }
}
void Field::AddAttr(AttrList* attrs) void Field::AddAttr(AttrList* attrs) {
{ bool delete_attrs = false;
bool delete_attrs = false;
if ( ! attrs_ ) if ( ! attrs_ ) {
{ attrs_ = attrs;
attrs_ = attrs; }
} else {
else attrs_->insert(attrs_->end(), attrs->begin(), attrs->end());
{ delete_attrs = true;
attrs_->insert(attrs_->end(), attrs->begin(), attrs->end()); }
delete_attrs = true;
}
foreach (i, AttrList, attrs) foreach (i, AttrList, attrs)
ProcessAttr(*i); ProcessAttr(*i);
if ( delete_attrs ) if ( delete_attrs )
delete attrs; delete attrs;
} }
void Field::ProcessAttr(Attr* a) void Field::ProcessAttr(Attr* a) {
{ switch ( a->type() ) {
switch ( a->type() ) case ATTR_IF:
{ if ( tof() != LET_FIELD && tof() != WITHINPUT_FIELD ) {
case ATTR_IF: throw Exception(a,
if ( tof() != LET_FIELD && tof() != WITHINPUT_FIELD ) "&if can only be applied to a "
{ "let field");
throw Exception(a, "&if can only be applied to a " }
"let field"); break;
} default: break;
break; }
default:
break;
}
if ( type_ ) if ( type_ )
type_->ProcessAttr(a); type_->ProcessAttr(a);
} }
bool Field::anonymous_field() const bool Field::anonymous_field() const { return type_ && type_->anonymous_value_var(); }
{
return type_ && type_->anonymous_value_var();
}
int Field::ValueVarType() const int Field::ValueVarType() const {
{ if ( flags_ & CLASS_MEMBER )
if ( flags_ & CLASS_MEMBER ) return (flags_ & PUBLIC_READABLE) ? MEMBER_VAR : PRIV_MEMBER_VAR;
return (flags_ & PUBLIC_READABLE) ? MEMBER_VAR : PRIV_MEMBER_VAR; else
else return TEMP_VAR;
return TEMP_VAR; }
}
void Field::Prepare(Env* env) void Field::Prepare(Env* env) {
{ if ( type_ ) {
if ( type_ ) if ( anonymous_field() )
{ flags_ &= ~(CLASS_MEMBER | PUBLIC_READABLE);
if ( anonymous_field() ) if ( ! type_->persistent() )
flags_ &= ~(CLASS_MEMBER | PUBLIC_READABLE); flags_ &= (~PUBLIC_READABLE);
if ( ! type_->persistent() )
flags_ &= (~PUBLIC_READABLE);
type_->set_value_var(id(), ValueVarType()); type_->set_value_var(id(), ValueVarType());
type_->Prepare(env, flags_ & TYPE_TO_BE_PARSED ? Type::TO_BE_PARSED : 0); type_->Prepare(env, flags_ & TYPE_TO_BE_PARSED ? Type::TO_BE_PARSED : 0);
env->SetField(id(), this); env->SetField(id(), this);
} }
} }
void Field::GenPubDecls(Output* out_h, Env* env) void Field::GenPubDecls(Output* out_h, Env* env) {
{ if ( type_ && (flags_ & PUBLIC_READABLE) && (flags_ & CLASS_MEMBER) )
if ( type_ && (flags_ & PUBLIC_READABLE) && (flags_ & CLASS_MEMBER) ) type_->GenPubDecls(out_h, env);
type_->GenPubDecls(out_h, env); }
}
void Field::GenPrivDecls(Output* out_h, Env* env) void Field::GenPrivDecls(Output* out_h, Env* env) {
{ // Generate private declaration only if it is a class member
// Generate private declaration only if it is a class member if ( type_ && (flags_ & CLASS_MEMBER) )
if ( type_ && (flags_ & CLASS_MEMBER) ) type_->GenPrivDecls(out_h, env);
type_->GenPrivDecls(out_h, env); }
}
void Field::GenTempDecls(Output* out_h, Env* env) void Field::GenTempDecls(Output* out_h, Env* env) {
{ // Generate temp field
// Generate temp field if ( type_ && ! (flags_ & CLASS_MEMBER) )
if ( type_ && ! (flags_ & CLASS_MEMBER) ) type_->GenPrivDecls(out_h, env);
type_->GenPrivDecls(out_h, env); }
}
void Field::GenInitCode(Output* out_cc, Env* env) void Field::GenInitCode(Output* out_cc, Env* env) {
{ if ( type_ && ! anonymous_field() )
if ( type_ && ! anonymous_field() ) type_->GenInitCode(out_cc, env);
type_->GenInitCode(out_cc, env); }
}
void Field::GenCleanUpCode(Output* out_cc, Env* env) void Field::GenCleanUpCode(Output* out_cc, Env* env) {
{ if ( type_ && ! anonymous_field() )
if ( type_ && ! anonymous_field() ) type_->GenCleanUpCode(out_cc, env);
type_->GenCleanUpCode(out_cc, env); }
}
bool Field::DoTraverse(DataDepVisitor* visitor) bool Field::DoTraverse(DataDepVisitor* visitor) {
{ // Check parameterized type
// Check parameterized type if ( type_ && ! type_->Traverse(visitor) )
if ( type_ && ! type_->Traverse(visitor) ) return false;
return false; foreach (i, AttrList, attrs_)
foreach (i, AttrList, attrs_) if ( ! (*i)->Traverse(visitor) )
if ( ! (*i)->Traverse(visitor) ) return false;
return false; return true;
return true; }
}
bool Field::RequiresAnalyzerContext() const bool Field::RequiresAnalyzerContext() const {
{ // Check parameterized type
// Check parameterized type if ( type_ && type_->RequiresAnalyzerContext() )
if ( type_ && type_->RequiresAnalyzerContext() ) return true;
return true; foreach (i, AttrList, attrs_)
foreach (i, AttrList, attrs_) if ( (*i)->RequiresAnalyzerContext() )
if ( (*i)->RequiresAnalyzerContext() ) return true;
return true; return false;
return false; }
}

View file

@ -6,80 +6,78 @@
// A "field" is a member of class. // A "field" is a member of class.
enum FieldType enum FieldType {
{ CASE_FIELD,
CASE_FIELD, CONTEXT_FIELD,
CONTEXT_FIELD, FLOW_FIELD,
FLOW_FIELD, LET_FIELD,
LET_FIELD, PADDING_FIELD,
PADDING_FIELD, PARAM_FIELD,
PARAM_FIELD, RECORD_FIELD,
RECORD_FIELD, PARSE_VAR_FIELD,
PARSE_VAR_FIELD, PRIV_VAR_FIELD,
PRIV_VAR_FIELD, PUB_VAR_FIELD,
PUB_VAR_FIELD, TEMP_VAR_FIELD,
TEMP_VAR_FIELD, WITHINPUT_FIELD,
WITHINPUT_FIELD, };
};
class Field : public Object, public DataDepElement class Field : public Object, public DataDepElement {
{
public: public:
Field(FieldType tof, int flags, ID* id, Type* type); Field(FieldType tof, int flags, ID* id, Type* type);
// Field flags // Field flags
// Whether the field will be evaluated by calling the Parse() // Whether the field will be evaluated by calling the Parse()
// function of the type // function of the type
static const int TYPE_TO_BE_PARSED = 1; static const int TYPE_TO_BE_PARSED = 1;
static const int TYPE_NOT_TO_BE_PARSED = 0; static const int TYPE_NOT_TO_BE_PARSED = 0;
// Whether the field is a member of the class or a temp // Whether the field is a member of the class or a temp
// variable // variable
static const int CLASS_MEMBER = 2; static const int CLASS_MEMBER = 2;
static const int NOT_CLASS_MEMBER = 0; static const int NOT_CLASS_MEMBER = 0;
// Whether the field is public readable // Whether the field is public readable
static const int PUBLIC_READABLE = 4; static const int PUBLIC_READABLE = 4;
static const int NOT_PUBLIC_READABLE = 0; static const int NOT_PUBLIC_READABLE = 0;
~Field() override; ~Field() override;
FieldType tof() const { return tof_; } FieldType tof() const { return tof_; }
const ID* id() const { return id_; } const ID* id() const { return id_; }
Type* type() const { return type_; } Type* type() const { return type_; }
const ID* decl_id() const { return decl_id_; } const ID* decl_id() const { return decl_id_; }
bool anonymous_field() const; bool anonymous_field() const;
void AddAttr(AttrList* attrs); void AddAttr(AttrList* attrs);
// The field interface // The field interface
virtual void ProcessAttr(Attr* attr); virtual void ProcessAttr(Attr* attr);
virtual void Prepare(Env* env); virtual void Prepare(Env* env);
virtual void GenPubDecls(Output* out, Env* env); virtual void GenPubDecls(Output* out, Env* env);
virtual void GenPrivDecls(Output* out, Env* env); virtual void GenPrivDecls(Output* out, Env* env);
virtual void GenTempDecls(Output* out, Env* env); virtual void GenTempDecls(Output* out, Env* env);
virtual void GenInitCode(Output* out, Env* env); virtual void GenInitCode(Output* out, Env* env);
virtual void GenCleanUpCode(Output* out, Env* env); virtual void GenCleanUpCode(Output* out, Env* env);
virtual bool RequiresAnalyzerContext() const; virtual bool RequiresAnalyzerContext() const;
protected: protected:
int ValueVarType() const; int ValueVarType() const;
bool ToBeParsed() const; bool ToBeParsed() const;
bool DoTraverse(DataDepVisitor* visitor) override; bool DoTraverse(DataDepVisitor* visitor) override;
protected: protected:
FieldType tof_; FieldType tof_;
int flags_; int flags_;
ID* id_; ID* id_;
Type* type_; Type* type_;
const ID* decl_id_; const ID* decl_id_;
string field_id_str_; string field_id_str_;
AttrList* attrs_; AttrList* attrs_;
}; };
#endif // pac_field_h #endif // pac_field_h

View file

@ -15,298 +15,257 @@
#include "pac_type.h" #include "pac_type.h"
#include "pac_varfield.h" #include "pac_varfield.h"
FlowDecl::FlowDecl(ID* id, ParamList* params, AnalyzerElementList* elemlist) FlowDecl::FlowDecl(ID* id, ParamList* params, AnalyzerElementList* elemlist) : AnalyzerDecl(id, FLOW, params) {
: AnalyzerDecl(id, FLOW, params) dataunit_ = nullptr;
{ conn_decl_ = nullptr;
dataunit_ = nullptr; flow_buffer_var_field_ = nullptr;
conn_decl_ = nullptr; AddElements(elemlist);
flow_buffer_var_field_ = nullptr; }
AddElements(elemlist);
}
FlowDecl::~FlowDecl() FlowDecl::~FlowDecl() {
{ delete flow_buffer_var_field_;
delete flow_buffer_var_field_; delete dataunit_;
delete dataunit_; }
}
ParameterizedType* FlowDecl::flow_buffer_type_ = nullptr; ParameterizedType* FlowDecl::flow_buffer_type_ = nullptr;
ParameterizedType* FlowDecl::flow_buffer_type() ParameterizedType* FlowDecl::flow_buffer_type() {
{ if ( ! flow_buffer_type_ ) {
if ( ! flow_buffer_type_ ) flow_buffer_type_ = new ParameterizedType(new ID(kFlowBufferClass), nullptr);
{ }
flow_buffer_type_ = new ParameterizedType(new ID(kFlowBufferClass), nullptr); return flow_buffer_type_;
} }
return flow_buffer_type_;
}
void FlowDecl::AddBaseClass(vector<string>* base_classes) const void FlowDecl::AddBaseClass(vector<string>* base_classes) const { base_classes->push_back("binpac::FlowAnalyzer"); }
{
base_classes->push_back("binpac::FlowAnalyzer");
}
void FlowDecl::ProcessFlowElement(AnalyzerFlow* flow_elem) void FlowDecl::ProcessFlowElement(AnalyzerFlow* flow_elem) {
{ throw Exception(flow_elem, "flow should be defined in only a connection declaration");
throw Exception(flow_elem, "flow should be defined in only a connection declaration"); }
}
void FlowDecl::ProcessDataUnitElement(AnalyzerDataUnit* dataunit_elem) void FlowDecl::ProcessDataUnitElement(AnalyzerDataUnit* dataunit_elem) {
{ if ( dataunit_ ) {
if ( dataunit_ ) throw Exception(dataunit_elem, "dataunit already defined");
{ }
throw Exception(dataunit_elem, "dataunit already defined"); dataunit_ = dataunit_elem;
}
dataunit_ = dataunit_elem;
if ( dataunit_->type() == AnalyzerDataUnit::FLOWUNIT ) if ( dataunit_->type() == AnalyzerDataUnit::FLOWUNIT ) {
{ dataunit_->data_type()->MarkIncrementalInput();
dataunit_->data_type()->MarkIncrementalInput();
flow_buffer_var_field_ = new PubVarField(flow_buffer_id->clone(), flow_buffer_var_field_ = new PubVarField(flow_buffer_id->clone(), FlowDecl::flow_buffer_type()->Clone());
FlowDecl::flow_buffer_type()->Clone()); type_->AddField(flow_buffer_var_field_);
type_->AddField(flow_buffer_var_field_);
ASSERT(AnalyzerContextDecl::current_analyzer_context()); ASSERT(AnalyzerContextDecl::current_analyzer_context());
AnalyzerContextDecl::current_analyzer_context()->AddFlowBuffer(); AnalyzerContextDecl::current_analyzer_context()->AddFlowBuffer();
// Add an argument to the context initiation // Add an argument to the context initiation
dataunit_->context_type()->AddParamArg(new Expr(flow_buffer_var_field_->id()->clone())); dataunit_->context_type()->AddParamArg(new Expr(flow_buffer_var_field_->id()->clone()));
} }
} }
void FlowDecl::Prepare() void FlowDecl::Prepare() {
{ // Add the connection parameter
// Add the connection parameter if ( ! conn_decl_ ) {
if ( ! conn_decl_ ) throw Exception(this, "no connection is not declared for the flow");
{ }
throw Exception(this, "no connection is not declared for the flow");
}
if ( ! params_ ) if ( ! params_ )
params_ = new ParamList(); params_ = new ParamList();
params_->insert(params_->begin(), new Param(connection_id->clone(), conn_decl_->DataType())); params_->insert(params_->begin(), new Param(connection_id->clone(), conn_decl_->DataType()));
AnalyzerDecl::Prepare(); AnalyzerDecl::Prepare();
dataunit_->Prepare(env_); dataunit_->Prepare(env_);
} }
void FlowDecl::GenPubDecls(Output* out_h, Output* out_cc) void FlowDecl::GenPubDecls(Output* out_h, Output* out_cc) { AnalyzerDecl::GenPubDecls(out_h, out_cc); }
{
AnalyzerDecl::GenPubDecls(out_h, out_cc);
}
void FlowDecl::GenPrivDecls(Output* out_h, Output* out_cc) void FlowDecl::GenPrivDecls(Output* out_h, Output* out_cc) {
{ // Declare the data unit
// Declare the data unit dataunit_->dataunit_var_field()->GenPrivDecls(out_h, env_);
dataunit_->dataunit_var_field()->GenPrivDecls(out_h, env_);
// Declare the analyzer context // Declare the analyzer context
dataunit_->context_var_field()->GenPrivDecls(out_h, env_); dataunit_->context_var_field()->GenPrivDecls(out_h, env_);
AnalyzerDecl::GenPrivDecls(out_h, out_cc); AnalyzerDecl::GenPrivDecls(out_h, out_cc);
} }
void FlowDecl::GenInitCode(Output* out_cc) void FlowDecl::GenInitCode(Output* out_cc) {
{ AnalyzerDecl::GenInitCode(out_cc);
AnalyzerDecl::GenInitCode(out_cc);
out_cc->println("%s = nullptr;", env_->LValue(dataunit_id)); out_cc->println("%s = nullptr;", env_->LValue(dataunit_id));
out_cc->println("%s = nullptr;", env_->LValue(analyzer_context_id)); out_cc->println("%s = nullptr;", env_->LValue(analyzer_context_id));
if ( dataunit_->type() == AnalyzerDataUnit::FLOWUNIT ) if ( dataunit_->type() == AnalyzerDataUnit::FLOWUNIT ) {
{ flow_buffer_var_field_->type()->GenPreParsing(out_cc, env_);
flow_buffer_var_field_->type()->GenPreParsing(out_cc, env_); env_->SetEvaluated(flow_buffer_var_field_->id());
env_->SetEvaluated(flow_buffer_var_field_->id()); }
} }
}
void FlowDecl::GenCleanUpCode(Output* out_cc) void FlowDecl::GenCleanUpCode(Output* out_cc) {
{ GenDeleteDataUnit(out_cc);
GenDeleteDataUnit(out_cc); AnalyzerDecl::GenCleanUpCode(out_cc);
AnalyzerDecl::GenCleanUpCode(out_cc); }
}
void FlowDecl::GenEOFFunc(Output* out_h, Output* out_cc) void FlowDecl::GenEOFFunc(Output* out_h, Output* out_cc) {
{ string proto = strfmt("%s()", kFlowEOF);
string proto = strfmt("%s()", kFlowEOF);
out_h->println("void %s;", proto.c_str()); out_h->println("void %s;", proto.c_str());
out_cc->println("void %s::%s", class_name().c_str(), proto.c_str()); out_cc->println("void %s::%s", class_name().c_str(), proto.c_str());
out_cc->inc_indent(); out_cc->inc_indent();
out_cc->println("{"); out_cc->println("{");
foreach (i, AnalyzerHelperList, eof_helpers_) foreach (i, AnalyzerHelperList, eof_helpers_) {
{ (*i)->GenCode(nullptr, out_cc, this);
(*i)->GenCode(nullptr, out_cc, this); }
}
if ( dataunit_->type() == AnalyzerDataUnit::FLOWUNIT ) if ( dataunit_->type() == AnalyzerDataUnit::FLOWUNIT ) {
{ out_cc->println("%s->set_eof();", env_->LValue(flow_buffer_id));
out_cc->println("%s->set_eof();", env_->LValue(flow_buffer_id)); out_cc->println("%s(nullptr, nullptr);", kNewData);
out_cc->println("%s(nullptr, nullptr);", kNewData); }
}
out_cc->println("}"); out_cc->println("}");
out_cc->dec_indent(); out_cc->dec_indent();
} }
void FlowDecl::GenGapFunc(Output* out_h, Output* out_cc) void FlowDecl::GenGapFunc(Output* out_h, Output* out_cc) {
{ string proto = strfmt("%s(int gap_length)", kFlowGap);
string proto = strfmt("%s(int gap_length)", kFlowGap);
out_h->println("void %s;", proto.c_str()); out_h->println("void %s;", proto.c_str());
out_cc->println("void %s::%s", class_name().c_str(), proto.c_str()); out_cc->println("void %s::%s", class_name().c_str(), proto.c_str());
out_cc->inc_indent(); out_cc->inc_indent();
out_cc->println("{"); out_cc->println("{");
if ( dataunit_->type() == AnalyzerDataUnit::FLOWUNIT ) if ( dataunit_->type() == AnalyzerDataUnit::FLOWUNIT ) {
{ out_cc->println("%s->NewGap(gap_length);", env_->LValue(flow_buffer_id));
out_cc->println("%s->NewGap(gap_length);", env_->LValue(flow_buffer_id)); }
}
out_cc->println("}"); out_cc->println("}");
out_cc->dec_indent(); out_cc->dec_indent();
} }
void FlowDecl::GenProcessFunc(Output* out_h, Output* out_cc) void FlowDecl::GenProcessFunc(Output* out_h, Output* out_cc) {
{ env_->AddID(begin_of_data, TEMP_VAR, extern_type_const_byteptr);
env_->AddID(begin_of_data, TEMP_VAR, extern_type_const_byteptr); env_->AddID(end_of_data, TEMP_VAR, extern_type_const_byteptr);
env_->AddID(end_of_data, TEMP_VAR, extern_type_const_byteptr);
string proto = strfmt("%s(const_byteptr %s, const_byteptr %s)", kNewData, string proto = strfmt("%s(const_byteptr %s, const_byteptr %s)", kNewData, env_->LValue(begin_of_data),
env_->LValue(begin_of_data), env_->LValue(end_of_data)); env_->LValue(end_of_data));
out_h->println("void %s;", proto.c_str()); out_h->println("void %s;", proto.c_str());
out_cc->println("void %s::%s", class_name().c_str(), proto.c_str()); out_cc->println("void %s::%s", class_name().c_str(), proto.c_str());
out_cc->inc_indent(); out_cc->inc_indent();
out_cc->println("{"); out_cc->println("{");
out_cc->println("try"); out_cc->println("try");
out_cc->inc_indent(); out_cc->inc_indent();
out_cc->println("{"); out_cc->println("{");
env_->SetEvaluated(begin_of_data); env_->SetEvaluated(begin_of_data);
env_->SetEvaluated(end_of_data); env_->SetEvaluated(end_of_data);
switch ( dataunit_->type() ) switch ( dataunit_->type() ) {
{ case AnalyzerDataUnit::DATAGRAM: GenCodeDatagram(out_cc); break;
case AnalyzerDataUnit::DATAGRAM: case AnalyzerDataUnit::FLOWUNIT: GenCodeFlowUnit(out_cc); break;
GenCodeDatagram(out_cc); default: ASSERT(0);
break; }
case AnalyzerDataUnit::FLOWUNIT:
GenCodeFlowUnit(out_cc);
break;
default:
ASSERT(0);
}
out_cc->println("}"); out_cc->println("}");
out_cc->dec_indent(); out_cc->dec_indent();
out_cc->println("catch ( binpac::Exception const &e )"); out_cc->println("catch ( binpac::Exception const &e )");
out_cc->inc_indent(); out_cc->inc_indent();
out_cc->println("{"); out_cc->println("{");
GenCleanUpCode(out_cc); GenCleanUpCode(out_cc);
if ( dataunit_->type() == AnalyzerDataUnit::FLOWUNIT ) if ( dataunit_->type() == AnalyzerDataUnit::FLOWUNIT ) {
{ out_cc->println("%s->DiscardData();", env_->LValue(flow_buffer_id));
out_cc->println("%s->DiscardData();", env_->LValue(flow_buffer_id)); }
} out_cc->println("throw e;");
out_cc->println("throw e;"); out_cc->println("}");
out_cc->println("}"); out_cc->dec_indent();
out_cc->dec_indent();
out_cc->println("}"); out_cc->println("}");
out_cc->dec_indent(); out_cc->dec_indent();
out_cc->println(""); out_cc->println("");
} }
void FlowDecl::GenNewDataUnit(Output* out_cc) void FlowDecl::GenNewDataUnit(Output* out_cc) {
{ Type* unit_datatype = dataunit_->data_type();
Type* unit_datatype = dataunit_->data_type(); // dataunit_->data_type()->GenPreParsing(out_cc, env_);
// dataunit_->data_type()->GenPreParsing(out_cc, env_); dataunit_->GenNewDataUnit(out_cc, env_);
dataunit_->GenNewDataUnit(out_cc, env_); if ( unit_datatype->buffer_input() && unit_datatype->buffer_mode() == Type::BUFFER_BY_LENGTH ) {
if ( unit_datatype->buffer_input() && unit_datatype->buffer_mode() == Type::BUFFER_BY_LENGTH ) out_cc->println("%s->NewFrame(0, false);", env_->LValue(flow_buffer_id));
{ }
out_cc->println("%s->NewFrame(0, false);", env_->LValue(flow_buffer_id)); dataunit_->GenNewContext(out_cc, env_);
} }
dataunit_->GenNewContext(out_cc, env_);
}
void FlowDecl::GenDeleteDataUnit(Output* out_cc) void FlowDecl::GenDeleteDataUnit(Output* out_cc) {
{ // Do not just delete dataunit, because we may just want to Unref it.
// Do not just delete dataunit, because we may just want to Unref it. // out_cc->println("delete %s;", env_->LValue(dataunit_id));
// out_cc->println("delete %s;", env_->LValue(dataunit_id)); dataunit_->data_type()->GenCleanUpCode(out_cc, env_);
dataunit_->data_type()->GenCleanUpCode(out_cc, env_); dataunit_->context_type()->GenCleanUpCode(out_cc, env_);
dataunit_->context_type()->GenCleanUpCode(out_cc, env_); }
}
void FlowDecl::GenCodeFlowUnit(Output* out_cc) void FlowDecl::GenCodeFlowUnit(Output* out_cc) {
{ Type* unit_datatype = dataunit_->data_type();
Type* unit_datatype = dataunit_->data_type();
out_cc->println("%s->NewData(%s, %s);", env_->LValue(flow_buffer_id), out_cc->println("%s->NewData(%s, %s);", env_->LValue(flow_buffer_id), env_->RValue(begin_of_data),
env_->RValue(begin_of_data), env_->RValue(end_of_data)); env_->RValue(end_of_data));
out_cc->println("while ( %s->data_available() && ", env_->LValue(flow_buffer_id)); out_cc->println("while ( %s->data_available() && ", env_->LValue(flow_buffer_id));
out_cc->inc_indent(); out_cc->inc_indent();
out_cc->println("( !%s->have_pending_request() || %s->ready() ) )", out_cc->println("( !%s->have_pending_request() || %s->ready() ) )", env_->LValue(flow_buffer_id),
env_->LValue(flow_buffer_id), env_->LValue(flow_buffer_id)); env_->LValue(flow_buffer_id));
out_cc->println("{"); out_cc->println("{");
// Generate a new dataunit if necessary // Generate a new dataunit if necessary
out_cc->println("if ( ! %s )", env_->LValue(dataunit_id)); out_cc->println("if ( ! %s )", env_->LValue(dataunit_id));
out_cc->inc_indent(); out_cc->inc_indent();
out_cc->println("{"); out_cc->println("{");
out_cc->println("BINPAC_ASSERT(!%s);", env_->LValue(analyzer_context_id)); out_cc->println("BINPAC_ASSERT(!%s);", env_->LValue(analyzer_context_id));
GenNewDataUnit(out_cc); GenNewDataUnit(out_cc);
out_cc->println("}"); out_cc->println("}");
out_cc->dec_indent(); out_cc->dec_indent();
DataPtr data(env_, nullptr, 0); DataPtr data(env_, nullptr, 0);
unit_datatype->GenParseCode(out_cc, env_, data, 0); unit_datatype->GenParseCode(out_cc, env_, data, 0);
out_cc->println("if ( %s )", unit_datatype->parsing_complete(env_).c_str()); out_cc->println("if ( %s )", unit_datatype->parsing_complete(env_).c_str());
out_cc->inc_indent(); out_cc->inc_indent();
out_cc->println("{"); out_cc->println("{");
out_cc->println("// Clean up the flow unit after parsing"); out_cc->println("// Clean up the flow unit after parsing");
GenDeleteDataUnit(out_cc); GenDeleteDataUnit(out_cc);
// out_cc->println("BINPAC_ASSERT(%s == 0);", env_->LValue(dataunit_id)); // out_cc->println("BINPAC_ASSERT(%s == 0);", env_->LValue(dataunit_id));
out_cc->println("}"); out_cc->println("}");
out_cc->dec_indent(); out_cc->dec_indent();
out_cc->println("else"); out_cc->println("else");
out_cc->inc_indent(); out_cc->inc_indent();
out_cc->println("{"); out_cc->println("{");
out_cc->println("// Resume upon next input segment"); out_cc->println("// Resume upon next input segment");
out_cc->println("BINPAC_ASSERT(!%s->ready());", env_->RValue(flow_buffer_id)); out_cc->println("BINPAC_ASSERT(!%s->ready());", env_->RValue(flow_buffer_id));
out_cc->println("break;"); out_cc->println("break;");
out_cc->println("}"); out_cc->println("}");
out_cc->dec_indent(); out_cc->dec_indent();
out_cc->println("}"); out_cc->println("}");
out_cc->dec_indent(); out_cc->dec_indent();
} }
void FlowDecl::GenCodeDatagram(Output* out_cc) void FlowDecl::GenCodeDatagram(Output* out_cc) {
{ Type* unit_datatype = dataunit_->data_type();
Type* unit_datatype = dataunit_->data_type(); GenNewDataUnit(out_cc);
GenNewDataUnit(out_cc);
string parse_params = strfmt("%s, %s", env_->RValue(begin_of_data), env_->RValue(end_of_data)); string parse_params = strfmt("%s, %s", env_->RValue(begin_of_data), env_->RValue(end_of_data));
if ( RequiresAnalyzerContext::compute(unit_datatype) ) if ( RequiresAnalyzerContext::compute(unit_datatype) ) {
{ parse_params += ", ";
parse_params += ", "; parse_params += env_->RValue(analyzer_context_id);
parse_params += env_->RValue(analyzer_context_id); }
}
DataPtr dataptr(env_, begin_of_data, 0); DataPtr dataptr(env_, begin_of_data, 0);
unit_datatype->GenParseCode(out_cc, env_, dataptr, 0); unit_datatype->GenParseCode(out_cc, env_, dataptr, 0);
GenDeleteDataUnit(out_cc); GenDeleteDataUnit(out_cc);
} }

View file

@ -3,45 +3,44 @@
#include "pac_analyzer.h" #include "pac_analyzer.h"
class FlowDecl : public AnalyzerDecl class FlowDecl : public AnalyzerDecl {
{
public: public:
FlowDecl(ID* flow_id, ParamList* params, AnalyzerElementList* elemlist); FlowDecl(ID* flow_id, ParamList* params, AnalyzerElementList* elemlist);
~FlowDecl() override; ~FlowDecl() override;
void Prepare() override; void Prepare() override;
void set_conn_decl(ConnDecl* c) { conn_decl_ = c; } void set_conn_decl(ConnDecl* c) { conn_decl_ = c; }
static ParameterizedType* flow_buffer_type(); static ParameterizedType* flow_buffer_type();
protected: protected:
void AddBaseClass(vector<string>* base_classes) const override; void AddBaseClass(vector<string>* base_classes) const override;
void GenInitCode(Output* out_cc) override; void GenInitCode(Output* out_cc) override;
void GenCleanUpCode(Output* out_cc) override; void GenCleanUpCode(Output* out_cc) override;
void GenProcessFunc(Output* out_h, Output* out_cc) override; void GenProcessFunc(Output* out_h, Output* out_cc) override;
void GenEOFFunc(Output* out_h, Output* out_cc) override; void GenEOFFunc(Output* out_h, Output* out_cc) override;
void GenGapFunc(Output* out_h, Output* out_cc) override; void GenGapFunc(Output* out_h, Output* out_cc) override;
void GenPubDecls(Output* out_h, Output* out_cc) override; void GenPubDecls(Output* out_h, Output* out_cc) override;
void GenPrivDecls(Output* out_h, Output* out_cc) override; void GenPrivDecls(Output* out_h, Output* out_cc) override;
void ProcessFlowElement(AnalyzerFlow* flow_elem) override; void ProcessFlowElement(AnalyzerFlow* flow_elem) override;
void ProcessDataUnitElement(AnalyzerDataUnit* dataunit_elem) override; void ProcessDataUnitElement(AnalyzerDataUnit* dataunit_elem) override;
private: private:
void GenNewDataUnit(Output* out_cc); void GenNewDataUnit(Output* out_cc);
void GenDeleteDataUnit(Output* out_cc); void GenDeleteDataUnit(Output* out_cc);
void GenCodeFlowUnit(Output* out_cc); void GenCodeFlowUnit(Output* out_cc);
void GenCodeDatagram(Output* out_cc); void GenCodeDatagram(Output* out_cc);
AnalyzerDataUnit* dataunit_; AnalyzerDataUnit* dataunit_;
ConnDecl* conn_decl_; ConnDecl* conn_decl_;
Field* flow_buffer_var_field_; Field* flow_buffer_var_field_;
static ParameterizedType* flow_buffer_type_; static ParameterizedType* flow_buffer_type_;
}; };
#endif // pac_flow_h #endif // pac_flow_h

View file

@ -7,109 +7,86 @@
#include "pac_type.h" #include "pac_type.h"
Function::Function(ID* id, Type* type, ParamList* params) Function::Function(ID* id, Type* type, ParamList* params)
: id_(id), type_(type), params_(params), expr_(nullptr), code_(nullptr) : id_(id), type_(type), params_(params), expr_(nullptr), code_(nullptr) {
{ analyzer_decl_ = nullptr;
analyzer_decl_ = nullptr; env_ = nullptr;
env_ = nullptr; }
}
Function::~Function() Function::~Function() {
{ delete id_;
delete id_; delete type_;
delete type_; delete_list(ParamList, params_);
delete_list(ParamList, params_); delete env_;
delete env_; delete expr_;
delete expr_; delete code_;
delete code_; }
}
void Function::Prepare(Env* env) void Function::Prepare(Env* env) {
{ env->AddID(id_, FUNC_ID, type_);
env->AddID(id_, FUNC_ID, type_); env->SetEvaluated(id_);
env->SetEvaluated(id_);
env_ = new Env(env, this); env_ = new Env(env, this);
foreach (i, ParamList, params_) foreach (i, ParamList, params_) {
{ Param* p = *i;
Param* p = *i; env_->AddID(p->id(), FUNC_PARAM, p->type());
env_->AddID(p->id(), FUNC_PARAM, p->type()); env_->SetEvaluated(p->id());
env_->SetEvaluated(p->id()); }
} }
}
void Function::GenForwardDeclaration(Output* out_h) void Function::GenForwardDeclaration(Output* out_h) {
{ // Do nothing
// Do nothing }
}
void Function::GenCode(Output* out_h, Output* out_cc) void Function::GenCode(Output* out_h, Output* out_cc) {
{ out_h->println("%s %s(%s);", type_->DataTypeStr().c_str(), id_->Name(), ParamDecls(params_).c_str());
out_h->println("%s %s(%s);", type_->DataTypeStr().c_str(), id_->Name(),
ParamDecls(params_).c_str());
string class_str = ""; string class_str = "";
if ( analyzer_decl_ ) if ( analyzer_decl_ )
class_str = strfmt("%s::", analyzer_decl_->id()->Name()); class_str = strfmt("%s::", analyzer_decl_->id()->Name());
string proto_str = strfmt("%s %s%s(%s)", type_->DataTypeStr().c_str(), class_str.c_str(), string proto_str = strfmt("%s %s%s(%s)", type_->DataTypeStr().c_str(), class_str.c_str(), id_->Name(),
id_->Name(), ParamDecls(params_).c_str()); ParamDecls(params_).c_str());
ASSERT(! (expr_ && code_)); ASSERT(! (expr_ && code_));
if ( expr_ ) if ( expr_ ) {
{ out_cc->println("%s", proto_str.c_str());
out_cc->println("%s", proto_str.c_str());
out_cc->inc_indent(); out_cc->inc_indent();
out_cc->println("{"); out_cc->println("{");
out_cc->println("return static_cast<%s>(%s);", type_->DataTypeStr().c_str(), out_cc->println("return static_cast<%s>(%s);", type_->DataTypeStr().c_str(), expr_->EvalExpr(out_cc, env_));
expr_->EvalExpr(out_cc, env_));
out_cc->println("}"); out_cc->println("}");
out_cc->dec_indent(); out_cc->dec_indent();
} }
else if ( code_ ) else if ( code_ ) {
{ out_cc->println("%s", proto_str.c_str());
out_cc->println("%s", proto_str.c_str());
out_cc->inc_indent(); out_cc->inc_indent();
out_cc->println("{"); out_cc->println("{");
code_->GenCode(out_cc, env_); code_->GenCode(out_cc, env_);
out_cc->println("}"); out_cc->println("}");
out_cc->dec_indent(); out_cc->dec_indent();
} }
out_cc->println(""); out_cc->println("");
} }
FuncDecl::FuncDecl(Function* function) : Decl(function->id()->clone(), FUNC), function_(function) FuncDecl::FuncDecl(Function* function) : Decl(function->id()->clone(), FUNC), function_(function) {
{ function_->Prepare(global_env());
function_->Prepare(global_env()); }
}
FuncDecl::~FuncDecl() FuncDecl::~FuncDecl() { delete function_; }
{
delete function_;
}
void FuncDecl::Prepare() { } void FuncDecl::Prepare() {}
void FuncDecl::GenForwardDeclaration(Output* out_h) void FuncDecl::GenForwardDeclaration(Output* out_h) { function_->GenForwardDeclaration(out_h); }
{
function_->GenForwardDeclaration(out_h);
}
void FuncDecl::GenCode(Output* out_h, Output* out_cc) void FuncDecl::GenCode(Output* out_h, Output* out_cc) { function_->GenCode(out_h, out_cc); }
{
function_->GenCode(out_h, out_cc);
}
AnalyzerFunction::AnalyzerFunction(Function* function) AnalyzerFunction::AnalyzerFunction(Function* function) : AnalyzerElement(FUNCTION), function_(function) {}
: AnalyzerElement(FUNCTION), function_(function)
{
}

View file

@ -4,65 +4,62 @@
#include "pac_analyzer.h" #include "pac_analyzer.h"
#include "pac_decl.h" #include "pac_decl.h"
class Function : public Object class Function : public Object {
{
public: public:
Function(ID* id, Type* type, ParamList* params); Function(ID* id, Type* type, ParamList* params);
~Function(); ~Function();
ID* id() const { return id_; } ID* id() const { return id_; }
AnalyzerDecl* analyzer_decl() const { return analyzer_decl_; } AnalyzerDecl* analyzer_decl() const { return analyzer_decl_; }
void set_analyzer_decl(AnalyzerDecl* decl) { analyzer_decl_ = decl; } void set_analyzer_decl(AnalyzerDecl* decl) { analyzer_decl_ = decl; }
Expr* expr() const { return expr_; } Expr* expr() const { return expr_; }
void set_expr(Expr* expr) { expr_ = expr; } void set_expr(Expr* expr) { expr_ = expr; }
EmbeddedCode* code() const { return code_; } EmbeddedCode* code() const { return code_; }
void set_code(EmbeddedCode* code) { code_ = code; } void set_code(EmbeddedCode* code) { code_ = code; }
void Prepare(Env* env); void Prepare(Env* env);
void GenForwardDeclaration(Output* out_h); void GenForwardDeclaration(Output* out_h);
void GenCode(Output* out_h, Output* out_cc); void GenCode(Output* out_h, Output* out_cc);
private: private:
Env* env_; Env* env_;
ID* id_; ID* id_;
Type* type_; Type* type_;
ParamList* params_; ParamList* params_;
AnalyzerDecl* analyzer_decl_; AnalyzerDecl* analyzer_decl_;
Expr* expr_; Expr* expr_;
EmbeddedCode* code_; EmbeddedCode* code_;
}; };
class FuncDecl : public Decl class FuncDecl : public Decl {
{
public: public:
FuncDecl(Function* function); FuncDecl(Function* function);
~FuncDecl() override; ~FuncDecl() override;
Function* function() const { return function_; } Function* function() const { return function_; }
void Prepare() override; void Prepare() override;
void GenForwardDeclaration(Output* out_h) override; void GenForwardDeclaration(Output* out_h) override;
void GenCode(Output* out_h, Output* out_cc) override; void GenCode(Output* out_h, Output* out_cc) override;
private: private:
Function* function_; Function* function_;
}; };
class AnalyzerFunction : public AnalyzerElement class AnalyzerFunction : public AnalyzerElement {
{
public: public:
AnalyzerFunction(Function* function); AnalyzerFunction(Function* function);
Function* function() const { return function_; } Function* function() const { return function_; }
private: private:
Function* function_; Function* function_;
}; };
#endif // pac_func_h #endif // pac_func_h

View file

@ -38,402 +38,338 @@ const ID* buffering_state_id = nullptr;
int ID::anonymous_id_seq = 0; int ID::anonymous_id_seq = 0;
ID* ID::NewAnonymousID(const string& prefix) ID* ID::NewAnonymousID(const string& prefix) {
{ ID* id = new ID(strfmt("%s%03d", prefix.c_str(), ++anonymous_id_seq));
ID* id = new ID(strfmt("%s%03d", prefix.c_str(), ++anonymous_id_seq)); id->anonymous_id_ = true;
id->anonymous_id_ = true; return id;
return id; }
}
IDRecord::IDRecord(Env* arg_env, const ID* arg_id, IDType arg_id_type) IDRecord::IDRecord(Env* arg_env, const ID* arg_id, IDType arg_id_type)
: env(arg_env), id(arg_id), id_type(arg_id_type) : env(arg_env), id(arg_id), id_type(arg_id_type) {
{ eval = nullptr;
eval = nullptr; evaluated = in_evaluation = false;
evaluated = in_evaluation = false; setfunc = ""; // except for STATE_VAR
setfunc = ""; // except for STATE_VAR switch ( id_type ) {
switch ( id_type ) case MEMBER_VAR:
{ rvalue = strfmt("%s()", id->Name());
case MEMBER_VAR: lvalue = strfmt("%s_", id->Name());
rvalue = strfmt("%s()", id->Name()); break;
lvalue = strfmt("%s_", id->Name()); case PRIV_MEMBER_VAR:
break; rvalue = strfmt("%s_", id->Name());
case PRIV_MEMBER_VAR: lvalue = strfmt("%s_", id->Name());
rvalue = strfmt("%s_", id->Name()); break;
lvalue = strfmt("%s_", id->Name()); case UNION_VAR:
break; rvalue = strfmt("%s()", id->Name());
case UNION_VAR: lvalue = strfmt("%s_", id->Name());
rvalue = strfmt("%s()", id->Name()); break;
lvalue = strfmt("%s_", id->Name()); case CONST:
break; case GLOBAL_VAR:
case CONST: rvalue = strfmt("%s", id->Name());
case GLOBAL_VAR: lvalue = strfmt("%s", id->Name());
rvalue = strfmt("%s", id->Name()); break;
lvalue = strfmt("%s", id->Name()); case TEMP_VAR:
break; rvalue = strfmt("t_%s", id->Name());
case TEMP_VAR: lvalue = strfmt("t_%s", id->Name());
rvalue = strfmt("t_%s", id->Name()); break;
lvalue = strfmt("t_%s", id->Name()); case STATE_VAR:
break; rvalue = strfmt("%s()", id->Name());
case STATE_VAR: lvalue = strfmt("%s_", id->Name());
rvalue = strfmt("%s()", id->Name()); break;
lvalue = strfmt("%s_", id->Name()); case MACRO:
break; rvalue = "@MACRO@";
case MACRO: lvalue = "@MACRO@";
rvalue = "@MACRO@"; break;
lvalue = "@MACRO@"; case FUNC_ID:
break; rvalue = strfmt("%s", id->Name());
case FUNC_ID: lvalue = "@FUNC_ID@";
rvalue = strfmt("%s", id->Name()); break;
lvalue = "@FUNC_ID@"; case FUNC_PARAM:
break; rvalue = strfmt("%s", id->Name());
case FUNC_PARAM: lvalue = "@FUNC_PARAM@";
rvalue = strfmt("%s", id->Name()); break;
lvalue = "@FUNC_PARAM@"; }
break;
}
data_type = nullptr; data_type = nullptr;
field = nullptr; field = nullptr;
constant = constant_set = false; constant = constant_set = false;
macro = nullptr; macro = nullptr;
} }
IDRecord::~IDRecord() { } IDRecord::~IDRecord() {}
void IDRecord::SetConstant(int c) void IDRecord::SetConstant(int c) {
{ ASSERT(id_type == CONST);
ASSERT(id_type == CONST); constant_set = true;
constant_set = true; constant = c;
constant = c; }
}
bool IDRecord::GetConstant(int* pc) const bool IDRecord::GetConstant(int* pc) const {
{ if ( constant_set )
if ( constant_set ) *pc = constant;
*pc = constant; return constant_set;
return constant_set; }
}
void IDRecord::SetMacro(Expr* e) void IDRecord::SetMacro(Expr* e) {
{ ASSERT(id_type == MACRO);
ASSERT(id_type == MACRO); macro = e;
macro = e; }
}
Expr* IDRecord::GetMacro() const Expr* IDRecord::GetMacro() const {
{ ASSERT(id_type == MACRO);
ASSERT(id_type == MACRO); return macro;
return macro; }
}
void IDRecord::SetEvaluated(bool v) void IDRecord::SetEvaluated(bool v) {
{ if ( v )
if ( v ) ASSERT(! evaluated);
ASSERT(! evaluated); evaluated = v;
evaluated = v; }
}
void IDRecord::Evaluate(Output* out, Env* env) void IDRecord::Evaluate(Output* out, Env* env) {
{ if ( evaluated )
if ( evaluated ) return;
return;
if ( ! out ) if ( ! out )
throw ExceptionIDNotEvaluated(id); throw ExceptionIDNotEvaluated(id);
if ( ! eval ) if ( ! eval )
throw Exception(id, "no evaluation method"); throw Exception(id, "no evaluation method");
if ( in_evaluation )
throw ExceptionCyclicDependence(id);
in_evaluation = true; if ( in_evaluation )
eval->GenEval(out, env); throw ExceptionCyclicDependence(id);
in_evaluation = false;
evaluated = true; in_evaluation = true;
} eval->GenEval(out, env);
in_evaluation = false;
const char* IDRecord::RValue() const evaluated = true;
{ }
if ( id_type == MACRO )
return macro->EvalExpr(nullptr, env);
if ( id_type == TEMP_VAR && ! evaluated ) const char* IDRecord::RValue() const {
throw ExceptionIDNotEvaluated(id); if ( id_type == MACRO )
return macro->EvalExpr(nullptr, env);
return rvalue.c_str(); if ( id_type == TEMP_VAR && ! evaluated )
} throw ExceptionIDNotEvaluated(id);
const char* IDRecord::LValue() const return rvalue.c_str();
{ }
ASSERT(id_type != MACRO && id_type != FUNC_ID);
return lvalue.c_str();
}
Env::Env(Env* parent_env, Object* context_object) const char* IDRecord::LValue() const {
: parent(parent_env), context_object_(context_object) ASSERT(id_type != MACRO && id_type != FUNC_ID);
{ return lvalue.c_str();
allow_undefined_id_ = false; }
in_branch_ = false;
}
Env::~Env() Env::Env(Env* parent_env, Object* context_object) : parent(parent_env), context_object_(context_object) {
{ allow_undefined_id_ = false;
for ( id_map_t::iterator it = id_map.begin(); it != id_map.end(); ++it ) in_branch_ = false;
{ }
delete it->second;
it->second = 0;
}
}
void Env::AddID(const ID* id, IDType id_type, Type* data_type) Env::~Env() {
{ for ( id_map_t::iterator it = id_map.begin(); it != id_map.end(); ++it ) {
DEBUG_MSG("To add ID `%s'...\n", id->Name()); delete it->second;
id_map_t::iterator it = id_map.find(id); it->second = 0;
if ( it != id_map.end() ) }
{ }
DEBUG_MSG("Duplicate definition: `%s'\n", it->first->Name());
throw ExceptionIDRedefinition(id);
}
id_map[id] = new IDRecord(this, id, id_type);
// TODO: figure out when data_type must be non-NULL
// ASSERT(data_type);
SetDataType(id, data_type);
}
void Env::AddConstID(const ID* id, const int c, Type* type) void Env::AddID(const ID* id, IDType id_type, Type* data_type) {
{ DEBUG_MSG("To add ID `%s'...\n", id->Name());
if ( ! type ) id_map_t::iterator it = id_map.find(id);
type = extern_type_int; if ( it != id_map.end() ) {
AddID(id, CONST, type); DEBUG_MSG("Duplicate definition: `%s'\n", it->first->Name());
SetConstant(id, c); throw ExceptionIDRedefinition(id);
SetEvaluated(id); // a constant is always evaluated }
} id_map[id] = new IDRecord(this, id, id_type);
// TODO: figure out when data_type must be non-NULL
// ASSERT(data_type);
SetDataType(id, data_type);
}
void Env::AddMacro(const ID* id, Expr* macro) void Env::AddConstID(const ID* id, const int c, Type* type) {
{ if ( ! type )
AddID(id, MACRO, macro->DataType(this)); type = extern_type_int;
SetMacro(id, macro); AddID(id, CONST, type);
SetEvaluated(id); SetConstant(id, c);
} SetEvaluated(id); // a constant is always evaluated
}
ID* Env::AddTempID(Type* type) void Env::AddMacro(const ID* id, Expr* macro) {
{ AddID(id, MACRO, macro->DataType(this));
ID* id = ID::NewAnonymousID("t_var_"); SetMacro(id, macro);
AddID(id, TEMP_VAR, type); SetEvaluated(id);
return id; }
}
IDRecord* Env::lookup(const ID* id, bool recursive, bool raise_exception) const ID* Env::AddTempID(Type* type) {
{ ID* id = ID::NewAnonymousID("t_var_");
ASSERT(id); AddID(id, TEMP_VAR, type);
return id;
}
id_map_t::const_iterator it = id_map.find(id); IDRecord* Env::lookup(const ID* id, bool recursive, bool raise_exception) const {
if ( it != id_map.end() ) ASSERT(id);
return it->second;
if ( recursive && parent ) id_map_t::const_iterator it = id_map.find(id);
return parent->lookup(id, recursive, raise_exception); if ( it != id_map.end() )
return it->second;
if ( raise_exception ) if ( recursive && parent )
throw ExceptionIDNotFound(id); return parent->lookup(id, recursive, raise_exception);
else
return nullptr;
}
IDType Env::GetIDType(const ID* id) const if ( raise_exception )
{ throw ExceptionIDNotFound(id);
return lookup(id, true, true)->GetType(); else
} return nullptr;
}
const char* Env::RValue(const ID* id) const IDType Env::GetIDType(const ID* id) const { return lookup(id, true, true)->GetType(); }
{
IDRecord* r = lookup(id, true, false);
if ( r )
return r->RValue();
else
{
if ( allow_undefined_id() )
return id->Name();
else
throw ExceptionIDNotFound(id);
}
}
const char* Env::LValue(const ID* id) const const char* Env::RValue(const ID* id) const {
{ IDRecord* r = lookup(id, true, false);
return lookup(id, true, true)->LValue(); if ( r )
} return r->RValue();
else {
if ( allow_undefined_id() )
return id->Name();
else
throw ExceptionIDNotFound(id);
}
}
void Env::SetEvalMethod(const ID* id, Evaluatable* eval) const char* Env::LValue(const ID* id) const { return lookup(id, true, true)->LValue(); }
{
lookup(id, true, true)->SetEvalMethod(eval);
}
void Env::Evaluate(Output* out, const ID* id) void Env::SetEvalMethod(const ID* id, Evaluatable* eval) { lookup(id, true, true)->SetEvalMethod(eval); }
{
IDRecord* r = lookup(id, true, ! allow_undefined_id());
if ( r )
r->Evaluate(out, this);
}
bool Env::Evaluated(const ID* id) const void Env::Evaluate(Output* out, const ID* id) {
{ IDRecord* r = lookup(id, true, ! allow_undefined_id());
IDRecord* r = lookup(id, true, ! allow_undefined_id()); if ( r )
if ( r ) r->Evaluate(out, this);
return r->Evaluated(); }
else
// Assume undefined variables are already evaluated
return true;
}
void Env::SetEvaluated(const ID* id, bool v) bool Env::Evaluated(const ID* id) const {
{ IDRecord* r = lookup(id, true, ! allow_undefined_id());
if ( in_branch() ) if ( r )
{ return r->Evaluated();
Field* f = GetField(id); else
if ( f && f->tof() == LET_FIELD ) // Assume undefined variables are already evaluated
{ return true;
throw Exception(context_object_, strfmt("INTERNAL ERROR: " }
"evaluating let field '%s' in a branch! "
"To work around this problem, "
"add '&requires(%s)' to the case type. "
"Sorry for the inconvenience.\n",
id->Name(), id->Name()));
ASSERT(0);
}
}
IDRecord* r = lookup(id, false, false); void Env::SetEvaluated(const ID* id, bool v) {
if ( r ) if ( in_branch() ) {
r->SetEvaluated(v); Field* f = GetField(id);
else if ( parent ) if ( f && f->tof() == LET_FIELD ) {
parent->SetEvaluated(id, v); throw Exception(context_object_, strfmt("INTERNAL ERROR: "
else "evaluating let field '%s' in a branch! "
throw ExceptionIDNotFound(id); "To work around this problem, "
} "add '&requires(%s)' to the case type. "
"Sorry for the inconvenience.\n",
id->Name(), id->Name()));
ASSERT(0);
}
}
void Env::SetField(const ID* id, Field* field) IDRecord* r = lookup(id, false, false);
{ if ( r )
lookup(id, false, true)->SetField(field); r->SetEvaluated(v);
} else if ( parent )
parent->SetEvaluated(id, v);
else
throw ExceptionIDNotFound(id);
}
Field* Env::GetField(const ID* id) const void Env::SetField(const ID* id, Field* field) { lookup(id, false, true)->SetField(field); }
{
return lookup(id, true, true)->GetField();
}
void Env::SetDataType(const ID* id, Type* type) Field* Env::GetField(const ID* id) const { return lookup(id, true, true)->GetField(); }
{
lookup(id, true, true)->SetDataType(type);
}
Type* Env::GetDataType(const ID* id) const void Env::SetDataType(const ID* id, Type* type) { lookup(id, true, true)->SetDataType(type); }
{
IDRecord* r = lookup(id, true, false);
if ( r )
return r->GetDataType();
else
return nullptr;
}
string Env::DataTypeStr(const ID* id) const Type* Env::GetDataType(const ID* id) const {
{ IDRecord* r = lookup(id, true, false);
Type* type = GetDataType(id); if ( r )
if ( ! type ) return r->GetDataType();
throw Exception(id, "data type not defined"); else
return type->DataTypeStr(); return nullptr;
} }
void Env::SetConstant(const ID* id, int constant) string Env::DataTypeStr(const ID* id) const {
{ Type* type = GetDataType(id);
lookup(id, false, true)->SetConstant(constant); if ( ! type )
} throw Exception(id, "data type not defined");
return type->DataTypeStr();
}
bool Env::GetConstant(const ID* id, int* pc) const void Env::SetConstant(const ID* id, int constant) { lookup(id, false, true)->SetConstant(constant); }
{
ASSERT(pc);
// lookup without raising exception
IDRecord* r = lookup(id, true, false);
if ( r )
return r->GetConstant(pc);
else
return false;
}
void Env::SetMacro(const ID* id, Expr* macro) bool Env::GetConstant(const ID* id, int* pc) const {
{ ASSERT(pc);
lookup(id, true, true)->SetMacro(macro); // lookup without raising exception
} IDRecord* r = lookup(id, true, false);
if ( r )
return r->GetConstant(pc);
else
return false;
}
Expr* Env::GetMacro(const ID* id) const void Env::SetMacro(const ID* id, Expr* macro) { lookup(id, true, true)->SetMacro(macro); }
{
return lookup(id, true, true)->GetMacro();
}
void init_builtin_identifiers() Expr* Env::GetMacro(const ID* id) const { return lookup(id, true, true)->GetMacro(); }
{
default_value_var = new ID("val");
null_id = new ID("NULL");
null_byteseg_id = new ID("null_byteseg");
begin_of_data = new ID("begin_of_data");
end_of_data = new ID("end_of_data");
len_of_data = new ID("length_of_data");
byteorder_id = new ID("byteorder");
bigendian_id = new ID("bigendian");
littleendian_id = new ID("littleendian");
unspecified_byteorder_id = new ID("unspecified_byteorder");
const_true_id = new ID("true");
const_false_id = new ID("false");
analyzer_context_id = new ID("context");
this_id = new ID("this");
sourcedata_id = new ID("sourcedata");
connection_id = new ID("connection");
upflow_id = new ID("upflow");
downflow_id = new ID("downflow");
dataunit_id = new ID("dataunit");
flow_buffer_id = new ID("flow_buffer");
element_macro_id = new ID("$element");
input_macro_id = new ID("$input");
context_macro_id = new ID("$context");
parsing_state_id = new ID("parsing_state");
buffering_state_id = new ID("buffering_state");
null_decl_id = new ID("<null-decl>"); void init_builtin_identifiers() {
current_decl_id = null_decl_id; default_value_var = new ID("val");
} null_id = new ID("NULL");
null_byteseg_id = new ID("null_byteseg");
begin_of_data = new ID("begin_of_data");
end_of_data = new ID("end_of_data");
len_of_data = new ID("length_of_data");
byteorder_id = new ID("byteorder");
bigendian_id = new ID("bigendian");
littleendian_id = new ID("littleendian");
unspecified_byteorder_id = new ID("unspecified_byteorder");
const_true_id = new ID("true");
const_false_id = new ID("false");
analyzer_context_id = new ID("context");
this_id = new ID("this");
sourcedata_id = new ID("sourcedata");
connection_id = new ID("connection");
upflow_id = new ID("upflow");
downflow_id = new ID("downflow");
dataunit_id = new ID("dataunit");
flow_buffer_id = new ID("flow_buffer");
element_macro_id = new ID("$element");
input_macro_id = new ID("$input");
context_macro_id = new ID("$context");
parsing_state_id = new ID("parsing_state");
buffering_state_id = new ID("buffering_state");
Env* global_env() null_decl_id = new ID("<null-decl>");
{ current_decl_id = null_decl_id;
static Env* the_global_env = nullptr; }
if ( ! the_global_env ) Env* global_env() {
{ static Env* the_global_env = nullptr;
the_global_env = new Env(nullptr, nullptr);
// These two are defined in binpac.h, so we do not need to if ( ! the_global_env ) {
// generate code for them. the_global_env = new Env(nullptr, nullptr);
the_global_env->AddConstID(bigendian_id, 0);
the_global_env->AddConstID(littleendian_id, 1); // These two are defined in binpac.h, so we do not need to
the_global_env->AddConstID(unspecified_byteorder_id, -1); // generate code for them.
the_global_env->AddConstID(const_false_id, 0); the_global_env->AddConstID(bigendian_id, 0);
the_global_env->AddConstID(const_true_id, 1); the_global_env->AddConstID(littleendian_id, 1);
// A hack for ID "this" the_global_env->AddConstID(unspecified_byteorder_id, -1);
the_global_env->AddConstID(this_id, 0); the_global_env->AddConstID(const_false_id, 0);
the_global_env->AddConstID(null_id, 0, extern_type_nullptr); the_global_env->AddConstID(const_true_id, 1);
// A hack for ID "this"
the_global_env->AddConstID(this_id, 0);
the_global_env->AddConstID(null_id, 0, extern_type_nullptr);
#if 0 #if 0
the_global_env->AddID(null_byteseg_id, the_global_env->AddID(null_byteseg_id,
GLOBAL_VAR, GLOBAL_VAR,
extern_type_const_byteseg); extern_type_const_byteseg);
#endif #endif
} }
return the_global_env; return the_global_env;
} }
string set_function(const ID* id) string set_function(const ID* id) { return strfmt("set_%s", id->Name()); }
{
return strfmt("set_%s", id->Name());
}

View file

@ -22,189 +22,179 @@ using namespace std;
// Env -- a mapping from ID names to their L/R-value expressions and evaluation // Env -- a mapping from ID names to their L/R-value expressions and evaluation
// methods. // methods.
enum IDType enum IDType {
{ CONST,
CONST, GLOBAL_VAR,
GLOBAL_VAR, TEMP_VAR,
TEMP_VAR, MEMBER_VAR,
MEMBER_VAR, PRIV_MEMBER_VAR,
PRIV_MEMBER_VAR, UNION_VAR,
UNION_VAR, STATE_VAR,
STATE_VAR, MACRO,
MACRO, FUNC_ID,
FUNC_ID, FUNC_PARAM,
FUNC_PARAM, };
};
class ID; class ID;
class IDRecord; class IDRecord;
class Env; class Env;
class Evaluatable; class Evaluatable;
class ID : public Object class ID : public Object {
{
public: public:
ID(string arg_name) : name(arg_name), anonymous_id_(false) ID(string arg_name) : name(arg_name), anonymous_id_(false) { locname = nfmt("%s:%s", Location(), Name()); }
{ ~ID() { delete[] locname; }
locname = nfmt("%s:%s", Location(), Name());
}
~ID() { delete[] locname; }
bool operator==(ID const& x) const { return name == x.Name(); } bool operator==(ID const& x) const { return name == x.Name(); }
const char* Name() const { return name.c_str(); } const char* Name() const { return name.c_str(); }
const char* LocName() const { return locname; } const char* LocName() const { return locname; }
bool is_anonymous() const { return anonymous_id_; } bool is_anonymous() const { return anonymous_id_; }
ID* clone() const { return new ID(Name()); } ID* clone() const { return new ID(Name()); }
protected: protected:
string name; string name;
bool anonymous_id_; bool anonymous_id_;
char* locname; char* locname;
friend class ID_ptr_cmp; friend class ID_ptr_cmp;
public: public:
static ID* NewAnonymousID(const string& prefix); static ID* NewAnonymousID(const string& prefix);
private: private:
static int anonymous_id_seq; static int anonymous_id_seq;
}; };
// A comparison operator for pointers to ID's. // A comparison operator for pointers to ID's.
class ID_ptr_cmp class ID_ptr_cmp {
{
public: public:
bool operator()(const ID* const& id1, const ID* const& id2) const bool operator()(const ID* const& id1, const ID* const& id2) const {
{ ASSERT(id1);
ASSERT(id1); ASSERT(id2);
ASSERT(id2); return id1->name < id2->name;
return id1->name < id2->name; }
} };
};
class IDRecord class IDRecord {
{
public: public:
IDRecord(Env* env, const ID* id, IDType id_type); IDRecord(Env* env, const ID* id, IDType id_type);
~IDRecord(); ~IDRecord();
IDType GetType() const { return id_type; } IDType GetType() const { return id_type; }
void SetDataType(Type* type) { data_type = type; } void SetDataType(Type* type) { data_type = type; }
Type* GetDataType() const { return data_type; } Type* GetDataType() const { return data_type; }
void SetEvalMethod(Evaluatable* arg_eval) { eval = arg_eval; } void SetEvalMethod(Evaluatable* arg_eval) { eval = arg_eval; }
void Evaluate(Output* out, Env* env); void Evaluate(Output* out, Env* env);
void SetEvaluated(bool v); void SetEvaluated(bool v);
bool Evaluated() const { return evaluated; } bool Evaluated() const { return evaluated; }
void SetField(Field* f) { field = f; } void SetField(Field* f) { field = f; }
Field* GetField() const { return field; } Field* GetField() const { return field; }
void SetConstant(int c); void SetConstant(int c);
bool GetConstant(int* pc) const; bool GetConstant(int* pc) const;
void SetMacro(Expr* expr); void SetMacro(Expr* expr);
Expr* GetMacro() const; Expr* GetMacro() const;
const char* RValue() const; const char* RValue() const;
const char* LValue() const; const char* LValue() const;
protected: protected:
Env* env; Env* env;
const ID* id; const ID* id;
IDType id_type; IDType id_type;
string rvalue; string rvalue;
string lvalue; string lvalue;
string setfunc; string setfunc;
Type* data_type; Type* data_type;
Field* field; Field* field;
int constant; int constant;
bool constant_set; bool constant_set;
Expr* macro; Expr* macro;
bool evaluated; bool evaluated;
bool in_evaluation; // to detect cyclic dependence bool in_evaluation; // to detect cyclic dependence
Evaluatable* eval; Evaluatable* eval;
}; };
class Evaluatable class Evaluatable {
{
public: public:
virtual ~Evaluatable() { } virtual ~Evaluatable() {}
virtual void GenEval(Output* out, Env* env) = 0; virtual void GenEval(Output* out, Env* env) = 0;
}; };
class Env class Env {
{
public: public:
Env(Env* parent_env, Object* context_object); Env(Env* parent_env, Object* context_object);
~Env(); ~Env();
bool allow_undefined_id() const { return allow_undefined_id_; } bool allow_undefined_id() const { return allow_undefined_id_; }
void set_allow_undefined_id(bool x) { allow_undefined_id_ = x; } void set_allow_undefined_id(bool x) { allow_undefined_id_ = x; }
bool in_branch() const { return in_branch_; } bool in_branch() const { return in_branch_; }
void set_in_branch(bool x) { in_branch_ = x; } void set_in_branch(bool x) { in_branch_ = x; }
void AddID(const ID* id, IDType id_type, Type* type); void AddID(const ID* id, IDType id_type, Type* type);
void AddConstID(const ID* id, const int c, Type* type = 0); void AddConstID(const ID* id, const int c, Type* type = 0);
void AddMacro(const ID* id, Expr* expr); void AddMacro(const ID* id, Expr* expr);
// Generate a temp ID with a unique name // Generate a temp ID with a unique name
ID* AddTempID(Type* type); ID* AddTempID(Type* type);
IDType GetIDType(const ID* id) const; IDType GetIDType(const ID* id) const;
const char* RValue(const ID* id) const; const char* RValue(const ID* id) const;
const char* LValue(const ID* id) const; const char* LValue(const ID* id) const;
// const char *SetFunc(const ID *id) const; // const char *SetFunc(const ID *id) const;
// Set evaluation method for the ID // Set evaluation method for the ID
void SetEvalMethod(const ID* id, Evaluatable* eval); void SetEvalMethod(const ID* id, Evaluatable* eval);
// Evaluate the ID according to the evaluation method. It // Evaluate the ID according to the evaluation method. It
// assumes the ID has an evaluation emthod. It does nothing // assumes the ID has an evaluation emthod. It does nothing
// if the ID has already been evaluated. // if the ID has already been evaluated.
void Evaluate(Output* out, const ID* id); void Evaluate(Output* out, const ID* id);
// Whether the ID has already been evaluated. // Whether the ID has already been evaluated.
bool Evaluated(const ID* id) const; bool Evaluated(const ID* id) const;
// Set the ID as evaluated (or not). // Set the ID as evaluated (or not).
void SetEvaluated(const ID* id, bool v = true); void SetEvaluated(const ID* id, bool v = true);
void SetField(const ID* id, Field* field); void SetField(const ID* id, Field* field);
Field* GetField(const ID* id) const; Field* GetField(const ID* id) const;
bool GetConstant(const ID* id, int* pc) const; bool GetConstant(const ID* id, int* pc) const;
Expr* GetMacro(const ID* id) const; Expr* GetMacro(const ID* id) const;
Type* GetDataType(const ID* id) const; Type* GetDataType(const ID* id) const;
string DataTypeStr(const ID* id) const; string DataTypeStr(const ID* id) const;
protected: protected:
IDRecord* lookup(const ID* id, bool recursive, bool raise_exception) const; IDRecord* lookup(const ID* id, bool recursive, bool raise_exception) const;
void SetDataType(const ID* id, Type* type); void SetDataType(const ID* id, Type* type);
void SetConstant(const ID* id, int constant); void SetConstant(const ID* id, int constant);
void SetMacro(const ID* id, Expr* macro); void SetMacro(const ID* id, Expr* macro);
private: private:
Env* parent; Env* parent;
Object* context_object_; Object* context_object_;
typedef map<const ID*, IDRecord*, ID_ptr_cmp> id_map_t; typedef map<const ID*, IDRecord*, ID_ptr_cmp> id_map_t;
id_map_t id_map; id_map_t id_map;
bool allow_undefined_id_; bool allow_undefined_id_;
bool in_branch_; bool in_branch_;
}; };
extern const ID* default_value_var; extern const ID* default_value_var;
extern const ID* null_id; extern const ID* null_id;

View file

@ -6,33 +6,28 @@
#include "pac_output.h" #include "pac_output.h"
#include "pac_type.h" #include "pac_type.h"
InputBuffer::InputBuffer(Expr* expr) : DataDepElement(INPUT_BUFFER), expr_(expr) { } InputBuffer::InputBuffer(Expr* expr) : DataDepElement(INPUT_BUFFER), expr_(expr) {}
bool InputBuffer::DoTraverse(DataDepVisitor* visitor) bool InputBuffer::DoTraverse(DataDepVisitor* visitor) {
{ if ( expr_ && ! expr_->Traverse(visitor) )
if ( expr_ && ! expr_->Traverse(visitor) ) return false;
return false; return true;
return true; }
}
bool InputBuffer::RequiresAnalyzerContext() const bool InputBuffer::RequiresAnalyzerContext() const { return expr_->RequiresAnalyzerContext(); }
{
return expr_->RequiresAnalyzerContext();
}
DataPtr InputBuffer::GenDataBeginEnd(Output* out_cc, Env* env) DataPtr InputBuffer::GenDataBeginEnd(Output* out_cc, Env* env) {
{ env->AddID(begin_of_data, TEMP_VAR, extern_type_const_byteptr);
env->AddID(begin_of_data, TEMP_VAR, extern_type_const_byteptr); env->AddID(end_of_data, TEMP_VAR, extern_type_const_byteptr);
env->AddID(end_of_data, TEMP_VAR, extern_type_const_byteptr);
out_cc->println("%s %s, %s;", extern_type_const_byteptr->DataTypeStr().c_str(), out_cc->println("%s %s, %s;", extern_type_const_byteptr->DataTypeStr().c_str(), env->LValue(begin_of_data),
env->LValue(begin_of_data), env->LValue(end_of_data)); env->LValue(end_of_data));
out_cc->println("get_pointers(%s, &%s, &%s);", expr_->EvalExpr(out_cc, env), out_cc->println("get_pointers(%s, &%s, &%s);", expr_->EvalExpr(out_cc, env), env->LValue(begin_of_data),
env->LValue(begin_of_data), env->LValue(end_of_data)); env->LValue(end_of_data));
env->SetEvaluated(begin_of_data); env->SetEvaluated(begin_of_data);
env->SetEvaluated(end_of_data); env->SetEvaluated(end_of_data);
return DataPtr(env, begin_of_data, 0); return DataPtr(env, begin_of_data, 0);
} }

View file

@ -6,19 +6,18 @@
class Expr; class Expr;
class InputBuffer : public Object, public DataDepElement class InputBuffer : public Object, public DataDepElement {
{
public: public:
InputBuffer(Expr* expr); InputBuffer(Expr* expr);
bool RequiresAnalyzerContext() const; bool RequiresAnalyzerContext() const;
DataPtr GenDataBeginEnd(Output* out_cc, Env* env); DataPtr GenDataBeginEnd(Output* out_cc, Env* env);
protected: protected:
bool DoTraverse(DataDepVisitor* visitor) override; bool DoTraverse(DataDepVisitor* visitor) override;
private: private:
Expr* expr_; Expr* expr_;
}; };
#endif // pac_inputbuf_h #endif // pac_inputbuf_h

View file

@ -5,143 +5,118 @@
#include "pac_output.h" #include "pac_output.h"
#include "pac_type.h" #include "pac_type.h"
namespace namespace {
{
void GenLetEval(const ID* id, Expr* expr, string prefix, Output* out, Env* env) { } void GenLetEval(const ID* id, Expr* expr, string prefix, Output* out, Env* env) {}
} // private namespace } // namespace
LetField::LetField(ID* id, Type* type, Expr* expr) LetField::LetField(ID* id, Type* type, Expr* expr)
: Field(LET_FIELD, TYPE_NOT_TO_BE_PARSED | CLASS_MEMBER | PUBLIC_READABLE, id, type), : Field(LET_FIELD, TYPE_NOT_TO_BE_PARSED | CLASS_MEMBER | PUBLIC_READABLE, id, type), expr_(expr) {
expr_(expr) ASSERT(expr_);
{ }
ASSERT(expr_);
}
LetField::~LetField() LetField::~LetField() { delete expr_; }
{
delete expr_;
}
bool LetField::DoTraverse(DataDepVisitor* visitor) bool LetField::DoTraverse(DataDepVisitor* visitor) { return Field::DoTraverse(visitor) && expr()->Traverse(visitor); }
{
return Field::DoTraverse(visitor) && expr()->Traverse(visitor);
}
bool LetField::RequiresAnalyzerContext() const bool LetField::RequiresAnalyzerContext() const {
{ return Field::RequiresAnalyzerContext() || (expr() && expr()->RequiresAnalyzerContext());
return Field::RequiresAnalyzerContext() || (expr() && expr()->RequiresAnalyzerContext()); }
}
void LetField::Prepare(Env* env) void LetField::Prepare(Env* env) {
{ if ( ! type_ ) {
if ( ! type_ ) ASSERT(expr_);
{ type_ = expr_->DataType(env);
ASSERT(expr_); if ( type_ )
type_ = expr_->DataType(env); type_ = type_->Clone();
if ( type_ ) else
type_ = type_->Clone(); type_ = extern_type_int->Clone();
else
type_ = extern_type_int->Clone();
foreach (i, AttrList, attrs_) foreach (i, AttrList, attrs_)
ProcessAttr(*i); ProcessAttr(*i);
} }
Field::Prepare(env); Field::Prepare(env);
env->SetEvalMethod(id_, this); env->SetEvalMethod(id_, this);
} }
void LetField::GenInitCode(Output* out_cc, Env* env) void LetField::GenInitCode(Output* out_cc, Env* env) {
{ int v;
int v; if ( expr_ && expr_->ConstFold(env, &v) ) {
if ( expr_ && expr_->ConstFold(env, &v) ) DEBUG_MSG("Folding const for `%s'\n", id_->Name());
{ GenEval(out_cc, env);
DEBUG_MSG("Folding const for `%s'\n", id_->Name()); }
GenEval(out_cc, env); else
} type_->GenInitCode(out_cc, env);
else }
type_->GenInitCode(out_cc, env);
}
void LetField::GenParseCode(Output* out_cc, Env* env) void LetField::GenParseCode(Output* out_cc, Env* env) {
{ if ( env->Evaluated(id_) )
if ( env->Evaluated(id_) ) return;
return;
if ( type_->attr_if_expr() ) if ( type_->attr_if_expr() ) {
{ // A conditional field
// A conditional field
env->Evaluate(out_cc, type_->has_value_var()); env->Evaluate(out_cc, type_->has_value_var());
// force evaluation of IDs contained in this expr // force evaluation of IDs contained in this expr
expr()->ForceIDEval(out_cc, env); expr()->ForceIDEval(out_cc, env);
out_cc->println("if ( %s )", env->RValue(type_->has_value_var())); out_cc->println("if ( %s )", env->RValue(type_->has_value_var()));
out_cc->inc_indent(); out_cc->inc_indent();
out_cc->println("{"); out_cc->println("{");
} }
out_cc->println("%s = %s;", env->LValue(id_), expr()->EvalExpr(out_cc, env)); out_cc->println("%s = %s;", env->LValue(id_), expr()->EvalExpr(out_cc, env));
if ( ! env->Evaluated(id_) ) if ( ! env->Evaluated(id_) )
env->SetEvaluated(id_); env->SetEvaluated(id_);
if ( type_->attr_if_expr() ) if ( type_->attr_if_expr() ) {
{ out_cc->println("}");
out_cc->println("}"); out_cc->dec_indent();
out_cc->dec_indent(); }
} }
}
void LetField::GenEval(Output* out_cc, Env* env) void LetField::GenEval(Output* out_cc, Env* env) { GenParseCode(out_cc, env); }
{
GenParseCode(out_cc, env);
}
LetDecl::LetDecl(ID* id, Type* type, Expr* expr) : Decl(id, LET), type_(type), expr_(expr) LetDecl::LetDecl(ID* id, Type* type, Expr* expr) : Decl(id, LET), type_(type), expr_(expr) {
{ if ( ! type_ ) {
if ( ! type_ ) ASSERT(expr_);
{ type_ = expr_->DataType(global_env());
ASSERT(expr_); if ( type_ )
type_ = expr_->DataType(global_env()); type_ = type_->Clone();
if ( type_ ) else
type_ = type_->Clone(); type_ = extern_type_int->Clone();
else }
type_ = extern_type_int->Clone();
}
Env* env = global_env(); Env* env = global_env();
int c; int c;
if ( expr_ && expr_->ConstFold(env, &c) ) if ( expr_ && expr_->ConstFold(env, &c) )
env->AddConstID(id_, c, type); env->AddConstID(id_, c, type);
else else
env->AddID(id_, GLOBAL_VAR, type_); env->AddID(id_, GLOBAL_VAR, type_);
} }
LetDecl::~LetDecl() LetDecl::~LetDecl() {
{ delete type_;
delete type_; delete expr_;
delete expr_; }
}
void LetDecl::Prepare() { } void LetDecl::Prepare() {}
void LetDecl::GenForwardDeclaration(Output* out_h) { } void LetDecl::GenForwardDeclaration(Output* out_h) {}
void LetDecl::GenCode(Output* out_h, Output* out_cc) void LetDecl::GenCode(Output* out_h, Output* out_cc) {
{ out_h->println("extern %s const %s;", type_->DataTypeStr().c_str(), global_env()->RValue(id_));
out_h->println("extern %s const %s;", type_->DataTypeStr().c_str(), global_env()->RValue(id_)); GenEval(out_cc, global_env());
GenEval(out_cc, global_env()); }
}
void LetDecl::GenEval(Output* out_cc, Env* /* env */) void LetDecl::GenEval(Output* out_cc, Env* /* env */) {
{ Env* env = global_env();
Env* env = global_env(); string tmp = strfmt("%s const", type_->DataTypeStr().c_str());
string tmp = strfmt("%s const", type_->DataTypeStr().c_str()); out_cc->println("%s %s = %s;", tmp.c_str(), env->LValue(id_), expr_->EvalExpr(out_cc, env));
out_cc->println("%s %s = %s;", tmp.c_str(), env->LValue(id_), expr_->EvalExpr(out_cc, env));
if ( ! env->Evaluated(id_) ) if ( ! env->Evaluated(id_) )
env->SetEvaluated(id_); env->SetEvaluated(id_);
} }

View file

@ -4,45 +4,43 @@
#include "pac_decl.h" #include "pac_decl.h"
#include "pac_field.h" #include "pac_field.h"
class LetField : public Field, Evaluatable class LetField : public Field, Evaluatable {
{
public: public:
LetField(ID* arg_id, Type* type, Expr* arg_expr); LetField(ID* arg_id, Type* type, Expr* arg_expr);
~LetField() override; ~LetField() override;
Expr* expr() const { return expr_; } Expr* expr() const { return expr_; }
void Prepare(Env* env) override; void Prepare(Env* env) override;
void GenInitCode(Output* out, Env* env) override; void GenInitCode(Output* out, Env* env) override;
void GenParseCode(Output* out, Env* env); void GenParseCode(Output* out, Env* env);
void GenEval(Output* out, Env* env) override; void GenEval(Output* out, Env* env) override;
bool RequiresAnalyzerContext() const override; bool RequiresAnalyzerContext() const override;
protected: protected:
bool DoTraverse(DataDepVisitor* visitor) override; bool DoTraverse(DataDepVisitor* visitor) override;
protected: protected:
Expr* expr_; Expr* expr_;
}; };
class LetDecl : public Decl, Evaluatable class LetDecl : public Decl, Evaluatable {
{
public: public:
LetDecl(ID* id, Type* type, Expr* expr); LetDecl(ID* id, Type* type, Expr* expr);
~LetDecl() override; ~LetDecl() override;
Expr* expr() const { return expr_; } Expr* expr() const { return expr_; }
void Prepare() override; void Prepare() override;
void GenForwardDeclaration(Output* out_h) override; void GenForwardDeclaration(Output* out_h) override;
void GenCode(Output* out_h, Output* out_cc) override; void GenCode(Output* out_h, Output* out_cc) override;
void GenEval(Output* out, Env* env) override; void GenEval(Output* out, Env* env) override;
private: private:
Type* type_; Type* type_;
Expr* expr_; Expr* expr_;
}; };
#endif // pac_let_h #endif // pac_let_h

View file

@ -25,185 +25,168 @@ vector<string> FLAGS_include_directories;
Output* header_output = nullptr; Output* header_output = nullptr;
Output* source_output = nullptr; Output* source_output = nullptr;
void add_to_include_directories(string dirs) void add_to_include_directories(string dirs) {
{ unsigned int dir_begin = 0, dir_end;
unsigned int dir_begin = 0, dir_end; while ( dir_begin < dirs.length() ) {
while ( dir_begin < dirs.length() ) for ( dir_end = dir_begin; dir_end < dirs.length(); ++dir_end )
{ if ( dirs[dir_end] == ':' )
for ( dir_end = dir_begin; dir_end < dirs.length(); ++dir_end ) break;
if ( dirs[dir_end] == ':' )
break;
string dir = dirs.substr(dir_begin, dir_end - dir_begin); string dir = dirs.substr(dir_begin, dir_end - dir_begin);
// Add a trailing '/' if necessary // Add a trailing '/' if necessary
if ( dir.length() > 0 && *(dir.end() - 1) != '/' ) if ( dir.length() > 0 && *(dir.end() - 1) != '/' )
dir += '/'; dir += '/';
FLAGS_include_directories.push_back(dir);
dir_begin = dir_end + 1;
}
}
void pac_init() FLAGS_include_directories.push_back(dir);
{ dir_begin = dir_end + 1;
init_builtin_identifiers(); }
Type::init(); }
}
void insert_comments(Output* out, const char* source_filename) void pac_init() {
{ init_builtin_identifiers();
out->println("// This file is automatically generated from %s.\n", source_filename); Type::init();
} }
void insert_basictype_defs(Output* out) void insert_comments(Output* out, const char* source_filename) {
{ out->println("// This file is automatically generated from %s.\n", source_filename);
out->println("#ifndef pac_type_defs"); }
out->println("#define pac_type_defs");
out->println("");
out->println("typedef char int8;");
out->println("typedef short int16;");
out->println("typedef long int32;");
out->println("typedef long long int64;");
out->println("typedef unsigned char uint8;");
out->println("typedef unsigned short uint16;");
out->println("typedef unsigned long uint32;");
out->println("typedef unsigned long long uint64;");
out->println("");
out->println("#endif /* pac_type_defs */");
out->println("");
}
void insert_byteorder_macros(Output* out) void insert_basictype_defs(Output* out) {
{ out->println("#ifndef pac_type_defs");
out->println("#define FixByteOrder16(x) (byteorder == HOST_BYTEORDER ? (x) : pac_swap16(x))"); out->println("#define pac_type_defs");
out->println("#define FixByteOrder32(x) (byteorder == HOST_BYTEORDER ? (x) : pac_swap32(x))"); out->println("");
out->println("#define FixByteOrder64(x) (byteorder == HOST_BYTEORDER ? (x) : pac_swap64(x))"); out->println("typedef char int8;");
out->println(""); out->println("typedef short int16;");
} out->println("typedef long int32;");
out->println("typedef long long int64;");
const char* to_id(const char* s) out->println("typedef unsigned char uint8;");
{ out->println("typedef unsigned short uint16;");
static char t[1024]; out->println("typedef unsigned long uint32;");
int i; out->println("typedef unsigned long long uint64;");
for ( i = 0; s[i] && i < (int)sizeof(t) - 1; ++i )
t[i] = isalnum(s[i]) ? s[i] : '_';
if ( isdigit(t[0]) )
t[0] = '_';
t[i] = '\0';
return t;
}
int compile(const char* filename) out->println("");
{ out->println("#endif /* pac_type_defs */");
FILE* fp_input = fopen(filename, "r"); out->println("");
if ( ! fp_input ) }
{
string tmp = strfmt("Error in opening %s", filename);
perror(tmp.c_str());
return -1;
}
input_filename = filename;
string basename; void insert_byteorder_macros(Output* out) {
out->println("#define FixByteOrder16(x) (byteorder == HOST_BYTEORDER ? (x) : pac_swap16(x))");
out->println("#define FixByteOrder32(x) (byteorder == HOST_BYTEORDER ? (x) : pac_swap32(x))");
out->println("#define FixByteOrder64(x) (byteorder == HOST_BYTEORDER ? (x) : pac_swap64(x))");
out->println("");
}
if ( ! FLAGS_output_directory.empty() ) const char* to_id(const char* s) {
{ static char t[1024];
// Strip leading directories of filename int i;
const char* last_slash = strrchr(filename, '/'); for ( i = 0; s[i] && i < (int)sizeof(t) - 1; ++i )
if ( last_slash ) t[i] = isalnum(s[i]) ? s[i] : '_';
basename = last_slash + 1; if ( isdigit(t[0]) )
else t[0] = '_';
basename = filename; t[i] = '\0';
basename = FLAGS_output_directory + "/" + basename; return t;
} }
else
basename = filename;
// If the file name ends with ".pac" int compile(const char* filename) {
if ( basename.length() > 4 && basename.substr(basename.length() - 4) == ".pac" ) FILE* fp_input = fopen(filename, "r");
{ if ( ! fp_input ) {
basename = basename.substr(0, basename.length() - 4); string tmp = strfmt("Error in opening %s", filename);
} perror(tmp.c_str());
return -1;
}
input_filename = filename;
basename += "_pac"; string basename;
DEBUG_MSG("Output file: %s.{h,cc}\n", basename.c_str()); if ( ! FLAGS_output_directory.empty() ) {
// Strip leading directories of filename
const char* last_slash = strrchr(filename, '/');
if ( last_slash )
basename = last_slash + 1;
else
basename = filename;
basename = FLAGS_output_directory + "/" + basename;
}
else
basename = filename;
int ret = 0; // If the file name ends with ".pac"
if ( basename.length() > 4 && basename.substr(basename.length() - 4) == ".pac" ) {
basename = basename.substr(0, basename.length() - 4);
}
try basename += "_pac";
{
switch_to_file(fp_input);
if ( yyparse() )
return 1;
Output out_h(strfmt("%s.h", basename.c_str())); DEBUG_MSG("Output file: %s.{h,cc}\n", basename.c_str());
Output out_cc(strfmt("%s.cc", basename.c_str()));
header_output = &out_h; int ret = 0;
source_output = &out_cc;
insert_comments(&out_h, filename); try {
insert_comments(&out_cc, filename); switch_to_file(fp_input);
if ( yyparse() )
return 1;
const char* filename_id = to_id(filename); Output out_h(strfmt("%s.h", basename.c_str()));
Output out_cc(strfmt("%s.cc", basename.c_str()));
out_h.println("#ifndef %s_h", filename_id); header_output = &out_h;
out_h.println("#define %s_h", filename_id); source_output = &out_cc;
out_h.println("");
out_h.println("#include <vector>");
out_h.println("");
out_h.println("#include \"binpac.h\"");
out_h.println("");
out_cc.println(""); insert_comments(&out_h, filename);
out_cc.println("#ifdef __clang__"); insert_comments(&out_cc, filename);
out_cc.println("#pragma clang diagnostic ignored \"-Wparentheses-equality\"");
out_cc.println("#endif");
out_cc.println("");
out_cc.println("#include \"%s.h\"\n", basename.c_str()); const char* filename_id = to_id(filename);
Decl::ProcessDecls(&out_h, &out_cc); out_h.println("#ifndef %s_h", filename_id);
out_h.println("#define %s_h", filename_id);
out_h.println("");
out_h.println("#include <vector>");
out_h.println("");
out_h.println("#include \"binpac.h\"");
out_h.println("");
out_h.println("#endif /* %s_h */", filename_id); out_cc.println("");
} out_cc.println("#ifdef __clang__");
catch ( OutputException& e ) out_cc.println("#pragma clang diagnostic ignored \"-Wparentheses-equality\"");
{ out_cc.println("#endif");
fprintf(stderr, "Error in compiling %s: %s\n", filename, e.errmsg()); out_cc.println("");
ret = 1;
}
catch ( Exception& e )
{
fprintf(stderr, "%s\n", e.msg());
exit(1);
}
header_output = nullptr; out_cc.println("#include \"%s.h\"\n", basename.c_str());
source_output = nullptr;
input_filename = "";
fclose(fp_input);
return ret; Decl::ProcessDecls(&out_h, &out_cc);
}
void usage() out_h.println("#endif /* %s_h */", filename_id);
{ } catch ( OutputException& e ) {
fprintf(stderr, "Error in compiling %s: %s\n", filename, e.errmsg());
ret = 1;
} catch ( Exception& e ) {
fprintf(stderr, "%s\n", e.msg());
exit(1);
}
header_output = nullptr;
source_output = nullptr;
input_filename = "";
fclose(fp_input);
return ret;
}
void usage() {
#ifdef BINPAC_VERSION #ifdef BINPAC_VERSION
fprintf(stderr, "binpac version %s\n", BINPAC_VERSION); fprintf(stderr, "binpac version %s\n", BINPAC_VERSION);
#endif #endif
fprintf(stderr, "usage: binpac [options] <pac files>\n"); fprintf(stderr, "usage: binpac [options] <pac files>\n");
fprintf(stderr, " <pac files> | pac-language input files\n"); fprintf(stderr, " <pac files> | pac-language input files\n");
fprintf(stderr, " -d <dir> | use given directory for compiler output\n"); fprintf(stderr, " -d <dir> | use given directory for compiler output\n");
fprintf(stderr, " -D | enable debugging output\n"); fprintf(stderr, " -D | enable debugging output\n");
fprintf(stderr, " -q | stay quiet\n"); fprintf(stderr, " -q | stay quiet\n");
fprintf(stderr, " -h | show command line help\n"); fprintf(stderr, " -h | show command line help\n");
fprintf(stderr, " -I <dir> | include <dir> in input file search path\n"); fprintf(stderr, " -I <dir> | include <dir> in input file search path\n");
exit(1); exit(1);
} }
// GCC uses __SANITIZE_ADDRESS__, Clang uses __has_feature // GCC uses __SANITIZE_ADDRESS__, Clang uses __has_feature
#if defined(__SANITIZE_ADDRESS__) #if defined(__SANITIZE_ADDRESS__)
@ -224,68 +207,56 @@ void usage()
#define BINPAC_LSAN_DISABLE() #define BINPAC_LSAN_DISABLE()
#endif #endif
int main(int argc, char* argv[]) int main(int argc, char* argv[]) {
{ // We generally do not care at all if binpac is leaking and other
// We generally do not care at all if binpac is leaking and other // projects that use it, like Zeek, only have their build tripped up
// projects that use it, like Zeek, only have their build tripped up // by the default behavior of LSAN to treat leaks as errors.
// by the default behavior of LSAN to treat leaks as errors. BINPAC_LSAN_DISABLE();
BINPAC_LSAN_DISABLE();
#ifdef HAVE_MALLOC_OPTIONS #ifdef HAVE_MALLOC_OPTIONS
extern char* malloc_options; extern char* malloc_options;
#endif #endif
int o; int o;
while ( (o = getopt(argc, argv, "DqI:d:h")) != -1 ) while ( (o = getopt(argc, argv, "DqI:d:h")) != -1 ) {
{ switch ( o ) {
switch ( o ) case 'D': yydebug = 1; FLAGS_pac_debug = true;
{
case 'D':
yydebug = 1;
FLAGS_pac_debug = true;
#ifdef HAVE_MALLOC_OPTIONS #ifdef HAVE_MALLOC_OPTIONS
malloc_options = "A"; malloc_options = "A";
#endif #endif
break; break;
case 'q':
FLAGS_quiet = true;
break;
case 'I': case 'q': FLAGS_quiet = true; break;
// Add to FLAGS_include_directories
add_to_include_directories(optarg);
break;
case 'd': case 'I':
FLAGS_output_directory = optarg; // Add to FLAGS_include_directories
break; add_to_include_directories(optarg);
break;
case 'h': case 'd': FLAGS_output_directory = optarg; break;
usage();
break;
}
}
// Strip the trailing '/'s case 'h': usage(); break;
while ( ! FLAGS_output_directory.empty() && *(FLAGS_output_directory.end() - 1) == '/' ) }
{ }
FLAGS_output_directory.erase(FLAGS_output_directory.end() - 1);
}
// Add the current directory to FLAGS_include_directories // Strip the trailing '/'s
add_to_include_directories("."); while ( ! FLAGS_output_directory.empty() && *(FLAGS_output_directory.end() - 1) == '/' ) {
FLAGS_output_directory.erase(FLAGS_output_directory.end() - 1);
}
pac_init(); // Add the current directory to FLAGS_include_directories
add_to_include_directories(".");
argc -= optind; pac_init();
argv += optind;
if ( argc == 0 )
compile("-");
int ret = 0; argc -= optind;
for ( int i = 0; i < argc; ++i ) argv += optind;
if ( compile(argv[i]) ) if ( argc == 0 )
ret = 1; compile("-");
return ret; int ret = 0;
} for ( int i = 0; i < argc; ++i )
if ( compile(argv[i]) )
ret = 1;
return ret;
}

View file

@ -3,17 +3,16 @@
#include "pac_common.h" #include "pac_common.h"
class Number : public Object class Number : public Object {
{
public: public:
Number(int arg_n) : s(strfmt("%d", arg_n)), n(arg_n) { } Number(int arg_n) : s(strfmt("%d", arg_n)), n(arg_n) {}
Number(const char* arg_s, int arg_n) : s(arg_s), n(arg_n) { } Number(const char* arg_s, int arg_n) : s(arg_s), n(arg_n) {}
const char* Str() const { return s.c_str(); } const char* Str() const { return s.c_str(); }
int Num() const { return n; } int Num() const { return n; }
protected: protected:
const string s; const string s;
const int n; const int n;
}; };
#endif // pac_number_h #endif // pac_number_h

View file

@ -7,77 +7,65 @@
#include "pac_utils.h" #include "pac_utils.h"
OutputException::OutputException(const char* arg_msg) OutputException::OutputException(const char* arg_msg) { msg = arg_msg; }
{
msg = arg_msg;
}
OutputException::~OutputException() { } OutputException::~OutputException() {}
Output::Output(string filename) Output::Output(string filename) {
{ fp = fopen(filename.c_str(), "w");
fp = fopen(filename.c_str(), "w"); if ( ! fp )
if ( ! fp ) throw OutputException(strerror(errno));
throw OutputException(strerror(errno)); indent_ = 0;
indent_ = 0; }
}
Output::~Output() Output::~Output() {
{ if ( fp )
if ( fp ) fclose(fp);
fclose(fp); }
}
int Output::print(const char* fmt, va_list ap) int Output::print(const char* fmt, va_list ap) {
{ int r = vfprintf(fp, fmt, ap);
int r = vfprintf(fp, fmt, ap); if ( r == -1 )
if ( r == -1 ) throw OutputException(strerror(errno));
throw OutputException(strerror(errno)); return r;
return r; }
}
int Output::print(const char* fmt, ...) int Output::print(const char* fmt, ...) {
{ va_list ap;
va_list ap; va_start(ap, fmt);
va_start(ap, fmt); int r = -1;
int r = -1;
try try {
{ r = print(fmt, ap);
r = print(fmt, ap); }
}
catch ( ... ) catch ( ... ) {
{ va_end(ap);
va_end(ap); throw;
throw; }
}
va_end(ap); va_end(ap);
return r; return r;
} }
int Output::println(const char* fmt, ...) int Output::println(const char* fmt, ...) {
{ for ( int i = 0; i < indent(); ++i )
for ( int i = 0; i < indent(); ++i ) fprintf(fp, "\t");
fprintf(fp, "\t");
va_list ap; va_list ap;
va_start(ap, fmt); va_start(ap, fmt);
int r = -1; int r = -1;
try try {
{ r = print(fmt, ap);
r = print(fmt, ap); }
}
catch ( ... ) catch ( ... ) {
{ va_end(ap);
va_end(ap); throw;
throw; }
}
va_end(ap); va_end(ap);
fprintf(fp, "\n"); fprintf(fp, "\n");
return r; return r;
} }

View file

@ -7,36 +7,34 @@
using namespace std; using namespace std;
class OutputException class OutputException {
{
public: public:
OutputException(const char* arg_msg); OutputException(const char* arg_msg);
~OutputException(); ~OutputException();
const char* errmsg() const { return msg.c_str(); } const char* errmsg() const { return msg.c_str(); }
protected: protected:
string msg; string msg;
}; };
class Output class Output {
{
public: public:
Output(string filename); Output(string filename);
~Output(); ~Output();
int println(const char* fmt, ...); int println(const char* fmt, ...);
int print(const char* fmt, ...); int print(const char* fmt, ...);
int indent() const { return indent_; } int indent() const { return indent_; }
void inc_indent() { ++indent_; } void inc_indent() { ++indent_; }
void dec_indent() { --indent_; } void dec_indent() { --indent_; }
protected: protected:
int print(const char* fmt, va_list ap); int print(const char* fmt, va_list ap);
FILE* fp; FILE* fp;
int indent_; int indent_;
}; };
#endif /* pac_output_h */ #endif /* pac_output_h */

View file

@ -8,55 +8,46 @@
#include "pac_type.h" #include "pac_type.h"
#include "pac_utils.h" #include "pac_utils.h"
Param::Param(ID* id, Type* type) : id_(id), type_(type) Param::Param(ID* id, Type* type) : id_(id), type_(type) {
{ if ( ! type_ )
if ( ! type_ ) type_ = extern_type_int->Clone();
type_ = extern_type_int->Clone();
decl_str_ = strfmt("%s %s", type_->DataTypeConstRefStr().c_str(), id_->Name()); decl_str_ = strfmt("%s %s", type_->DataTypeConstRefStr().c_str(), id_->Name());
param_field_ = new ParamField(this); param_field_ = new ParamField(this);
} }
Param::~Param() { } Param::~Param() {}
const string& Param::decl_str() const const string& Param::decl_str() const {
{ ASSERT(! decl_str_.empty());
ASSERT(! decl_str_.empty()); return decl_str_;
return decl_str_; }
}
string ParamDecls(ParamList* params) string ParamDecls(ParamList* params) {
{ string param_decls;
string param_decls;
int first = 1; int first = 1;
foreach (i, ParamList, params) foreach (i, ParamList, params) {
{ Param* p = *i;
Param* p = *i; const char* decl_str = p->decl_str().c_str();
const char* decl_str = p->decl_str().c_str(); if ( first )
if ( first ) first = 0;
first = 0; else
else param_decls += ", ";
param_decls += ", "; param_decls += decl_str;
param_decls += decl_str; }
} return param_decls;
return param_decls; }
}
ParamField::ParamField(const Param* param) ParamField::ParamField(const Param* param)
: Field(PARAM_FIELD, TYPE_NOT_TO_BE_PARSED | CLASS_MEMBER | PUBLIC_READABLE, param->id(), : Field(PARAM_FIELD, TYPE_NOT_TO_BE_PARSED | CLASS_MEMBER | PUBLIC_READABLE, param->id(), param->type()) {}
param->type())
{
}
void ParamField::GenInitCode(Output* out_cc, Env* env) void ParamField::GenInitCode(Output* out_cc, Env* env) {
{ out_cc->println("%s = %s;", env->LValue(id()), id()->Name());
out_cc->println("%s = %s;", env->LValue(id()), id()->Name()); env->SetEvaluated(id());
env->SetEvaluated(id()); }
}
void ParamField::GenCleanUpCode(Output* out_cc, Env* env) void ParamField::GenCleanUpCode(Output* out_cc, Env* env) {
{ // Do nothing
// Do nothing }
}

View file

@ -4,32 +4,30 @@
#include "pac_common.h" #include "pac_common.h"
#include "pac_field.h" #include "pac_field.h"
class Param : public Object class Param : public Object {
{
public: public:
Param(ID* id, Type* type); Param(ID* id, Type* type);
~Param(); ~Param();
ID* id() const { return id_; } ID* id() const { return id_; }
Type* type() const { return type_; } Type* type() const { return type_; }
const string& decl_str() const; const string& decl_str() const;
Field* param_field() const { return param_field_; } Field* param_field() const { return param_field_; }
private: private:
ID* id_; ID* id_;
Type* type_; Type* type_;
string decl_str_; string decl_str_;
Field* param_field_; Field* param_field_;
}; };
class ParamField : public Field class ParamField : public Field {
{
public: public:
ParamField(const Param* param); ParamField(const Param* param);
void GenInitCode(Output* out, Env* env) override; void GenInitCode(Output* out, Env* env) override;
void GenCleanUpCode(Output* out, Env* env) override; void GenCleanUpCode(Output* out, Env* env) override;
}; };
// Returns the string with a list of param declarations separated by ','. // Returns the string with a list of param declarations separated by ','.
string ParamDecls(ParamList* params); string ParamDecls(ParamList* params);

View file

@ -8,266 +8,214 @@
#include "pac_typedecl.h" #include "pac_typedecl.h"
ParameterizedType::ParameterizedType(ID* type_id, ExprList* args) ParameterizedType::ParameterizedType(ID* type_id, ExprList* args)
: Type(PARAMETERIZED), type_id_(type_id), args_(args) : Type(PARAMETERIZED), type_id_(type_id), args_(args) {
{ checking_requires_analyzer_context_ = false;
checking_requires_analyzer_context_ = false; }
}
ParameterizedType::~ParameterizedType() { } ParameterizedType::~ParameterizedType() {}
string ParameterizedType::EvalMember(const ID* member_id) const string ParameterizedType::EvalMember(const ID* member_id) const {
{ Type* ty = ReferredDataType(true);
Type* ty = ReferredDataType(true); return strfmt("->%s", ty->env()->RValue(member_id));
return strfmt("->%s", ty->env()->RValue(member_id)); }
}
string ParameterizedType::class_name() const string ParameterizedType::class_name() const { return type_id_->Name(); }
{
return type_id_->Name();
}
Type* ParameterizedType::DoClone() const Type* ParameterizedType::DoClone() const { return new ParameterizedType(type_id_->clone(), args_); }
{
return new ParameterizedType(type_id_->clone(), args_);
}
void ParameterizedType::AddParamArg(Expr* arg) void ParameterizedType::AddParamArg(Expr* arg) { args_->push_back(arg); }
{
args_->push_back(arg);
}
bool ParameterizedType::DefineValueVar() const bool ParameterizedType::DefineValueVar() const { return true; }
{
return true;
}
string ParameterizedType::DataTypeStr() const string ParameterizedType::DataTypeStr() const { return strfmt("%s *", type_id_->Name()); }
{
return strfmt("%s *", type_id_->Name());
}
Type* ParameterizedType::MemberDataType(const ID* member_id) const Type* ParameterizedType::MemberDataType(const ID* member_id) const {
{ Type* ref_type = TypeDecl::LookUpType(type_id_);
Type* ref_type = TypeDecl::LookUpType(type_id_); if ( ! ref_type )
if ( ! ref_type ) return nullptr;
return nullptr; return ref_type->MemberDataType(member_id);
return ref_type->MemberDataType(member_id); }
}
Type* ParameterizedType::ReferredDataType(bool throw_exception) const Type* ParameterizedType::ReferredDataType(bool throw_exception) const {
{ Type* type = TypeDecl::LookUpType(type_id_);
Type* type = TypeDecl::LookUpType(type_id_); if ( ! type ) {
if ( ! type ) DEBUG_MSG("WARNING: cannot find referenced type for %s\n", type_id_->Name());
{ if ( throw_exception )
DEBUG_MSG("WARNING: cannot find referenced type for %s\n", type_id_->Name()); throw ExceptionIDNotFound(type_id_);
if ( throw_exception ) }
throw ExceptionIDNotFound(type_id_); return type;
} }
return type;
}
int ParameterizedType::StaticSize(Env* env) const int ParameterizedType::StaticSize(Env* env) const { return ReferredDataType(true)->StaticSize(env); }
{
return ReferredDataType(true)->StaticSize(env);
}
void ParameterizedType::DoMarkIncrementalInput() void ParameterizedType::DoMarkIncrementalInput() {
{ Type* ty = ReferredDataType(true);
Type* ty = ReferredDataType(true);
ty->MarkIncrementalInput(); ty->MarkIncrementalInput();
buffer_input_ = ty->buffer_input(); buffer_input_ = ty->buffer_input();
incremental_parsing_ = ty->incremental_parsing(); incremental_parsing_ = ty->incremental_parsing();
} }
Type::BufferMode ParameterizedType::buffer_mode() const Type::BufferMode ParameterizedType::buffer_mode() const {
{ // Note that the precedence is on attributes (&oneline or &length)
// Note that the precedence is on attributes (&oneline or &length) // specified on the parameterized type directly than on the type
// specified on the parameterized type directly than on the type // declaration.
// declaration. //
// // If both &oneline and &length are specified at the same place,
// If both &oneline and &length are specified at the same place, // use &length.
// use &length. //
// BufferMode mode = Type::buffer_mode();
BufferMode mode = Type::buffer_mode(); Type* ty = ReferredDataType(true);
Type* ty = ReferredDataType(true);
if ( mode != NOT_BUFFERABLE ) if ( mode != NOT_BUFFERABLE )
return mode; return mode;
else if ( ty->BufferableByLength() ) else if ( ty->BufferableByLength() )
return BUFFER_BY_LENGTH; return BUFFER_BY_LENGTH;
else if ( ty->BufferableByLine() ) else if ( ty->BufferableByLine() )
return BUFFER_BY_LINE; return BUFFER_BY_LINE;
return NOT_BUFFERABLE; return NOT_BUFFERABLE;
} }
bool ParameterizedType::ByteOrderSensitive() const bool ParameterizedType::ByteOrderSensitive() const { return ReferredDataType(true)->RequiresByteOrder(); }
{
return ReferredDataType(true)->RequiresByteOrder();
}
bool ParameterizedType::DoTraverse(DataDepVisitor* visitor) bool ParameterizedType::DoTraverse(DataDepVisitor* visitor) {
{ if ( ! Type::DoTraverse(visitor) )
if ( ! Type::DoTraverse(visitor) ) return false;
return false;
foreach (i, ExprList, args_) foreach (i, ExprList, args_)
if ( ! (*i)->Traverse(visitor) ) if ( ! (*i)->Traverse(visitor) )
return false; return false;
Type* ty = ReferredDataType(false); Type* ty = ReferredDataType(false);
if ( ty && ! ty->Traverse(visitor) ) if ( ty && ! ty->Traverse(visitor) )
return false; return false;
return true; return true;
} }
bool ParameterizedType::RequiresAnalyzerContext() bool ParameterizedType::RequiresAnalyzerContext() {
{ if ( checking_requires_analyzer_context_ )
if ( checking_requires_analyzer_context_ ) return false;
return false; checking_requires_analyzer_context_ = true;
checking_requires_analyzer_context_ = true;
bool ret = false; bool ret = false;
// If any argument expression refers to analyzer context // If any argument expression refers to analyzer context
foreach (i, ExprList, args_) foreach (i, ExprList, args_)
if ( (*i)->RequiresAnalyzerContext() ) if ( (*i)->RequiresAnalyzerContext() ) {
{ ret = true;
ret = true; break;
break; }
} ret = ret || Type::RequiresAnalyzerContext();
ret = ret || Type::RequiresAnalyzerContext();
if ( ! ret ) if ( ! ret ) {
{ Type* ty = ReferredDataType(false);
Type* ty = ReferredDataType(false); if ( ty )
if ( ty ) ret = ty->RequiresAnalyzerContext();
ret = ty->RequiresAnalyzerContext(); }
}
checking_requires_analyzer_context_ = false; checking_requires_analyzer_context_ = false;
return ret; return ret;
} }
void ParameterizedType::GenInitCode(Output* out_cc, Env* env) void ParameterizedType::GenInitCode(Output* out_cc, Env* env) {
{ ASSERT(persistent());
ASSERT(persistent()); out_cc->println("%s = nullptr;", env->LValue(value_var()));
out_cc->println("%s = nullptr;", env->LValue(value_var())); Type::GenInitCode(out_cc, env);
Type::GenInitCode(out_cc, env); }
}
void ParameterizedType::GenCleanUpCode(Output* out_cc, Env* env) void ParameterizedType::GenCleanUpCode(Output* out_cc, Env* env) {
{ Type* ty = ReferredDataType(false);
Type* ty = ReferredDataType(false); if ( ty && ty->attr_refcount() )
if ( ty && ty->attr_refcount() ) out_cc->println("Unref(%s);", lvalue());
out_cc->println("Unref(%s);", lvalue()); else
else out_cc->println("delete %s;", lvalue());
out_cc->println("delete %s;", lvalue()); out_cc->println("%s = nullptr;", lvalue());
out_cc->println("%s = nullptr;", lvalue()); Type::GenCleanUpCode(out_cc, env);
Type::GenCleanUpCode(out_cc, env); }
}
string ParameterizedType::EvalParameters(Output* out_cc, Env* env) const string ParameterizedType::EvalParameters(Output* out_cc, Env* env) const {
{ string arg_str;
string arg_str;
int first = 1; int first = 1;
foreach (i, ExprList, args_) foreach (i, ExprList, args_) {
{ Expr* e = *i;
Expr* e = *i; if ( first )
if ( first ) first = 0;
first = 0; else
else arg_str += ", ";
arg_str += ", "; arg_str += e->EvalExpr(out_cc, env);
arg_str += e->EvalExpr(out_cc, env); }
}
return arg_str; return arg_str;
} }
void ParameterizedType::GenNewInstance(Output* out_cc, Env* env) void ParameterizedType::GenNewInstance(Output* out_cc, Env* env) {
{ out_cc->println("%s = new %s(%s);", lvalue(), type_id_->Name(), EvalParameters(out_cc, env).c_str());
out_cc->println("%s = new %s(%s);", lvalue(), type_id_->Name(), }
EvalParameters(out_cc, env).c_str());
}
void ParameterizedType::DoGenParseCode(Output* out_cc, Env* env, const DataPtr& data, int flags) void ParameterizedType::DoGenParseCode(Output* out_cc, Env* env, const DataPtr& data, int flags) {
{ DEBUG_MSG("DoGenParseCode for %s\n", type_id_->Name());
DEBUG_MSG("DoGenParseCode for %s\n", type_id_->Name());
Type* ref_type = ReferredDataType(true); Type* ref_type = ReferredDataType(true);
const char* parse_func; const char* parse_func;
string parse_params; string parse_params;
if ( buffer_mode() == BUFFER_NOTHING ) if ( buffer_mode() == BUFFER_NOTHING ) {
{ ASSERT(! ref_type->incremental_input());
ASSERT(! ref_type->incremental_input()); parse_func = kParseFuncWithoutBuffer;
parse_func = kParseFuncWithoutBuffer; parse_params = "nullptr, nullptr";
parse_params = "nullptr, nullptr"; }
} else if ( ref_type->incremental_input() ) {
else if ( ref_type->incremental_input() ) parse_func = kParseFuncWithBuffer;
{ parse_params = env->RValue(flow_buffer_id);
parse_func = kParseFuncWithBuffer; }
parse_params = env->RValue(flow_buffer_id); else {
} parse_func = kParseFuncWithoutBuffer;
else parse_params = strfmt("%s, %s", data.ptr_expr(), env->RValue(end_of_data));
{ }
parse_func = kParseFuncWithoutBuffer;
parse_params = strfmt("%s, %s", data.ptr_expr(), env->RValue(end_of_data));
}
if ( RequiresAnalyzerContext::compute(ref_type) ) if ( RequiresAnalyzerContext::compute(ref_type) ) {
{ parse_params += strfmt(", %s", env->RValue(analyzer_context_id));
parse_params += strfmt(", %s", env->RValue(analyzer_context_id)); }
}
if ( ref_type->RequiresByteOrder() ) if ( ref_type->RequiresByteOrder() ) {
{ env->Evaluate(out_cc, byteorder_id);
env->Evaluate(out_cc, byteorder_id); parse_params += strfmt(", %s", env->RValue(byteorder_id));
parse_params += strfmt(", %s", env->RValue(byteorder_id)); }
}
string call_parse_func = strfmt("%s->%s(%s)", string call_parse_func = strfmt("%s->%s(%s)",
lvalue(), // parse() needs an LValue lvalue(), // parse() needs an LValue
parse_func, parse_params.c_str()); parse_func, parse_params.c_str());
if ( incremental_input() ) if ( incremental_input() ) {
{ if ( buffer_mode() == BUFFER_NOTHING ) {
if ( buffer_mode() == BUFFER_NOTHING ) out_cc->println("%s;", call_parse_func.c_str());
{ out_cc->println("%s = true;", env->LValue(parsing_complete_var()));
out_cc->println("%s;", call_parse_func.c_str()); }
out_cc->println("%s = true;", env->LValue(parsing_complete_var())); else {
} ASSERT(parsing_complete_var());
else out_cc->println("%s = %s;", env->LValue(parsing_complete_var()), call_parse_func.c_str());
{
ASSERT(parsing_complete_var());
out_cc->println("%s = %s;", env->LValue(parsing_complete_var()),
call_parse_func.c_str());
// parsing_complete_var might have been already // parsing_complete_var might have been already
// evaluated when set to false // evaluated when set to false
if ( ! env->Evaluated(parsing_complete_var()) ) if ( ! env->Evaluated(parsing_complete_var()) )
env->SetEvaluated(parsing_complete_var()); env->SetEvaluated(parsing_complete_var());
} }
} }
else else {
{ if ( AddSizeVar(out_cc, env) ) {
if ( AddSizeVar(out_cc, env) ) out_cc->println("%s = %s;", env->LValue(size_var()), call_parse_func.c_str());
{ env->SetEvaluated(size_var());
out_cc->println("%s = %s;", env->LValue(size_var()), call_parse_func.c_str()); }
env->SetEvaluated(size_var()); else {
} out_cc->println("%s;", call_parse_func.c_str());
else }
{ }
out_cc->println("%s;", call_parse_func.c_str()); }
}
}
}
void ParameterizedType::GenDynamicSize(Output* out_cc, Env* env, const DataPtr& data) void ParameterizedType::GenDynamicSize(Output* out_cc, Env* env, const DataPtr& data) {
{ GenParseCode(out_cc, env, data, 0);
GenParseCode(out_cc, env, data, 0); }
}

View file

@ -4,58 +4,57 @@
#include "pac_type.h" #include "pac_type.h"
// An instantiated type: ID + expression list // An instantiated type: ID + expression list
class ParameterizedType : public Type class ParameterizedType : public Type {
{
public: public:
ParameterizedType(ID* type_id, ExprList* args); ParameterizedType(ID* type_id, ExprList* args);
~ParameterizedType() override; ~ParameterizedType() override;
Type* clone() const; Type* clone() const;
string EvalMember(const ID* member_id) const override; string EvalMember(const ID* member_id) const override;
// Env *member_env() const; // Env *member_env() const;
void AddParamArg(Expr* arg); void AddParamArg(Expr* arg);
bool DefineValueVar() const override; bool DefineValueVar() const override;
string DataTypeStr() const override; string DataTypeStr() const override;
string DefaultValue() const override { return "0"; } string DefaultValue() const override { return "0"; }
Type* MemberDataType(const ID* member_id) const override; Type* MemberDataType(const ID* member_id) const override;
// "throw_exception" specifies whether to throw an exception // "throw_exception" specifies whether to throw an exception
// if the referred data type is not found // if the referred data type is not found
Type* ReferredDataType(bool throw_exception) const; Type* ReferredDataType(bool throw_exception) const;
void GenCleanUpCode(Output* out, Env* env) override; void GenCleanUpCode(Output* out, Env* env) override;
int StaticSize(Env* env) const override; int StaticSize(Env* env) const override;
bool IsPointerType() const override { return true; } bool IsPointerType() const override { return true; }
bool ByteOrderSensitive() const override; bool ByteOrderSensitive() const override;
bool RequiresAnalyzerContext() override; bool RequiresAnalyzerContext() override;
void GenInitCode(Output* out_cc, Env* env) override; void GenInitCode(Output* out_cc, Env* env) override;
string class_name() const; string class_name() const;
string EvalParameters(Output* out_cc, Env* env) const; string EvalParameters(Output* out_cc, Env* env) const;
BufferMode buffer_mode() const override; BufferMode buffer_mode() const override;
protected: protected:
void GenNewInstance(Output* out, Env* env) override; void GenNewInstance(Output* out, Env* env) override;
bool DoTraverse(DataDepVisitor* visitor) override; bool DoTraverse(DataDepVisitor* visitor) override;
Type* DoClone() const override; Type* DoClone() const override;
void DoMarkIncrementalInput() override; void DoMarkIncrementalInput() override;
private: private:
ID* type_id_; ID* type_id_;
ExprList* args_; ExprList* args_;
bool checking_requires_analyzer_context_; bool checking_requires_analyzer_context_;
void DoGenParseCode(Output* out, Env* env, const DataPtr& data, int flags) override; void DoGenParseCode(Output* out, Env* env, const DataPtr& data, int flags) override;
void GenDynamicSize(Output* out, Env* env, const DataPtr& data) override; void GenDynamicSize(Output* out, Env* env, const DataPtr& data) override;
}; };
#endif // pac_paramtype_h #endif // pac_paramtype_h

View file

@ -5,30 +5,26 @@
#include "pac_id.h" #include "pac_id.h"
#include "pac_type.h" #include "pac_type.h"
string PPVal::ToCode(Env* env) string PPVal::ToCode(Env* env) {
{ ASSERT(expr_);
ASSERT(expr_); return string(expr_->EvalExpr(nullptr, env));
return string(expr_->EvalExpr(nullptr, env)); }
}
string PPSet::ToCode(Env* env) string PPSet::ToCode(Env* env) {
{ ASSERT(expr_);
ASSERT(expr_); return expr_->SetFunc(nullptr, env);
return expr_->SetFunc(nullptr, env); }
}
string PPType::ToCode(Env* env) string PPType::ToCode(Env* env) {
{ Type* type = expr_->DataType(env);
Type* type = expr_->DataType(env); return type->DataTypeStr();
return type->DataTypeStr(); }
}
string PPConstDef::ToCode(Env* env) string PPConstDef::ToCode(Env* env) {
{ Type* type = expr_->DataType(env);
Type* type = expr_->DataType(env); env->AddID(id_, TEMP_VAR, type);
env->AddID(id_, TEMP_VAR, type); env->SetEvaluated(id_);
env->SetEvaluated(id_);
string type_str = type->DataTypeStr(); string type_str = type->DataTypeStr();
return strfmt("%s %s = %s", type_str.c_str(), env->LValue(id_), expr_->EvalExpr(nullptr, env)); return strfmt("%s %s = %s", type_str.c_str(), env->LValue(id_), expr_->EvalExpr(nullptr, env));
} }

View file

@ -3,76 +3,65 @@
#include "pac_common.h" #include "pac_common.h"
class PacPrimitive class PacPrimitive {
{
public: public:
enum PrimitiveType enum PrimitiveType { VAL, SET, TYPE, CONST_DEF };
{
VAL,
SET,
TYPE,
CONST_DEF
};
explicit PacPrimitive(PrimitiveType type) : type_(type) { } explicit PacPrimitive(PrimitiveType type) : type_(type) {}
virtual ~PacPrimitive() { } virtual ~PacPrimitive() {}
PrimitiveType type() const { return type_; } PrimitiveType type() const { return type_; }
virtual string ToCode(Env* env) = 0; virtual string ToCode(Env* env) = 0;
private: private:
PrimitiveType type_; PrimitiveType type_;
}; };
class PPVal : public PacPrimitive class PPVal : public PacPrimitive {
{
public: public:
PPVal(Expr* expr) : PacPrimitive(VAL), expr_(expr) { } PPVal(Expr* expr) : PacPrimitive(VAL), expr_(expr) {}
Expr* expr() const { return expr_; } Expr* expr() const { return expr_; }
string ToCode(Env* env) override; string ToCode(Env* env) override;
private: private:
Expr* expr_; Expr* expr_;
}; };
class PPSet : public PacPrimitive class PPSet : public PacPrimitive {
{
public: public:
PPSet(Expr* expr) : PacPrimitive(SET), expr_(expr) { } PPSet(Expr* expr) : PacPrimitive(SET), expr_(expr) {}
Expr* expr() const { return expr_; } Expr* expr() const { return expr_; }
string ToCode(Env* env) override; string ToCode(Env* env) override;
private: private:
Expr* expr_; Expr* expr_;
}; };
class PPType : public PacPrimitive class PPType : public PacPrimitive {
{
public: public:
PPType(Expr* expr) : PacPrimitive(TYPE), expr_(expr) { } PPType(Expr* expr) : PacPrimitive(TYPE), expr_(expr) {}
Expr* expr() const { return expr_; } Expr* expr() const { return expr_; }
string ToCode(Env* env) override; string ToCode(Env* env) override;
private: private:
Expr* expr_; Expr* expr_;
}; };
class PPConstDef : public PacPrimitive class PPConstDef : public PacPrimitive {
{
public: public:
PPConstDef(const ID* id, Expr* expr) : PacPrimitive(CONST_DEF), id_(id), expr_(expr) { } PPConstDef(const ID* id, Expr* expr) : PacPrimitive(CONST_DEF), id_(id), expr_(expr) {}
const ID* id() const { return id_; } const ID* id() const { return id_; }
Expr* expr() const { return expr_; } Expr* expr() const { return expr_; }
string ToCode(Env* env) override; string ToCode(Env* env) override;
private: private:
const ID* id_; const ID* id_;
Expr* expr_; Expr* expr_;
}; };
#endif // pac_primitive_h #endif // pac_primitive_h

File diff suppressed because it is too large Load diff

View file

@ -7,179 +7,165 @@
#include "pac_let.h" #include "pac_let.h"
#include "pac_type.h" #include "pac_type.h"
class RecordType : public Type class RecordType : public Type {
{
public: public:
RecordType(RecordFieldList* fields); RecordType(RecordFieldList* fields);
~RecordType() override; ~RecordType() override;
bool DefineValueVar() const override; bool DefineValueVar() const override;
string DataTypeStr() const override; string DataTypeStr() const override;
void Prepare(Env* env, int flags) override; void Prepare(Env* env, int flags) override;
void GenPubDecls(Output* out, Env* env) override; void GenPubDecls(Output* out, Env* env) override;
void GenPrivDecls(Output* out, Env* env) override; void GenPrivDecls(Output* out, Env* env) override;
void GenInitCode(Output* out, Env* env) override; void GenInitCode(Output* out, Env* env) override;
void GenCleanUpCode(Output* out, Env* env) override; void GenCleanUpCode(Output* out, Env* env) override;
int StaticSize(Env* env) const override; int StaticSize(Env* env) const override;
void SetBoundaryChecked() override; void SetBoundaryChecked() override;
const ID* parsing_dataptr_var() const; const ID* parsing_dataptr_var() const;
bool IsPointerType() const override bool IsPointerType() const override {
{ ASSERT(0);
ASSERT(0); return false;
return false; }
}
protected: protected:
void DoGenParseCode(Output* out, Env* env, const DataPtr& data, int flags) override; void DoGenParseCode(Output* out, Env* env, const DataPtr& data, int flags) override;
void GenDynamicSize(Output* out, Env* env, const DataPtr& data) override; void GenDynamicSize(Output* out, Env* env, const DataPtr& data) override;
Type* DoClone() const override { return nullptr; } Type* DoClone() const override { return nullptr; }
void DoMarkIncrementalInput() override; void DoMarkIncrementalInput() override;
bool DoTraverse(DataDepVisitor* visitor) override; bool DoTraverse(DataDepVisitor* visitor) override;
bool ByteOrderSensitive() const override; bool ByteOrderSensitive() const override;
private: private:
Field* parsing_dataptr_var_field_; Field* parsing_dataptr_var_field_;
RecordFieldList* record_fields_; RecordFieldList* record_fields_;
}; };
// A data field of a record type. A RecordField corresponds to a // A data field of a record type. A RecordField corresponds to a
// segment of input data, and therefore RecordField's are ordered---each // segment of input data, and therefore RecordField's are ordered---each
// of them has a known previous and next field. // of them has a known previous and next field.
class RecordField : public Field class RecordField : public Field {
{
public: public:
RecordField(FieldType tof, ID* id, Type* type); RecordField(FieldType tof, ID* id, Type* type);
~RecordField() override; ~RecordField() override;
RecordType* record_type() const { return record_type_; } RecordType* record_type() const { return record_type_; }
void set_record_type(RecordType* ty) { record_type_ = ty; } void set_record_type(RecordType* ty) { record_type_ = ty; }
virtual void GenParseCode(Output* out, Env* env) = 0; virtual void GenParseCode(Output* out, Env* env) = 0;
RecordField* prev() const { return prev_; } RecordField* prev() const { return prev_; }
RecordField* next() const { return next_; } RecordField* next() const { return next_; }
void set_prev(RecordField* f) { prev_ = f; } void set_prev(RecordField* f) { prev_ = f; }
void set_next(RecordField* f) { next_ = f; } void set_next(RecordField* f) { next_ = f; }
int static_offset() const { return static_offset_; } int static_offset() const { return static_offset_; }
void set_static_offset(int offset) { static_offset_ = offset; } void set_static_offset(int offset) { static_offset_ = offset; }
int parsing_state_seq() const { return parsing_state_seq_; } int parsing_state_seq() const { return parsing_state_seq_; }
void set_parsing_state_seq(int x) { parsing_state_seq_ = x; } void set_parsing_state_seq(int x) { parsing_state_seq_ = x; }
virtual int StaticSize(Env* env, int offset) const = 0; virtual int StaticSize(Env* env, int offset) const = 0;
const char* FieldSize(Output* out, Env* env); const char* FieldSize(Output* out, Env* env);
const char* FieldOffset(Output* out, Env* env); const char* FieldOffset(Output* out, Env* env);
virtual bool BoundaryChecked() const { return boundary_checked_; } virtual bool BoundaryChecked() const { return boundary_checked_; }
virtual void SetBoundaryChecked() { boundary_checked_ = true; } virtual void SetBoundaryChecked() { boundary_checked_ = true; }
virtual bool RequiresByteOrder() const = 0; virtual bool RequiresByteOrder() const = 0;
friend class RecordType; friend class RecordType;
protected: protected:
RecordType* record_type_; RecordType* record_type_;
RecordField* prev_; RecordField* prev_;
RecordField* next_; RecordField* next_;
bool boundary_checked_; bool boundary_checked_;
int static_offset_; int static_offset_;
int parsing_state_seq_; int parsing_state_seq_;
DataPtr* begin_of_field_dataptr; DataPtr* begin_of_field_dataptr;
DataPtr* end_of_field_dataptr; DataPtr* end_of_field_dataptr;
char* field_size_expr; char* field_size_expr;
char* field_offset_expr; char* field_offset_expr;
ID* end_of_field_dataptr_var; ID* end_of_field_dataptr_var;
const DataPtr& getFieldBegin(Output* out_cc, Env* env); const DataPtr& getFieldBegin(Output* out_cc, Env* env);
const DataPtr& getFieldEnd(Output* out_cc, Env* env); const DataPtr& getFieldEnd(Output* out_cc, Env* env);
virtual void GenFieldEnd(Output* out, Env* env, const DataPtr& begin) = 0; virtual void GenFieldEnd(Output* out, Env* env, const DataPtr& begin) = 0;
bool AttemptBoundaryCheck(Output* out_cc, Env* env); bool AttemptBoundaryCheck(Output* out_cc, Env* env);
virtual bool GenBoundaryCheck(Output* out_cc, Env* env) = 0; virtual bool GenBoundaryCheck(Output* out_cc, Env* env) = 0;
}; };
class RecordDataField : public RecordField, public Evaluatable class RecordDataField : public RecordField, public Evaluatable {
{
public: public:
RecordDataField(ID* arg_id, Type* arg_type); RecordDataField(ID* arg_id, Type* arg_type);
~RecordDataField() override; ~RecordDataField() override;
// Instantiates abstract class Field // Instantiates abstract class Field
void Prepare(Env* env) override; void Prepare(Env* env) override;
void GenParseCode(Output* out, Env* env) override; void GenParseCode(Output* out, Env* env) override;
// Instantiates abstract class Evaluatable // Instantiates abstract class Evaluatable
void GenEval(Output* out, Env* env) override; void GenEval(Output* out, Env* env) override;
int StaticSize(Env* env, int) const override { return type()->StaticSize(env); } int StaticSize(Env* env, int) const override { return type()->StaticSize(env); }
void SetBoundaryChecked() override; void SetBoundaryChecked() override;
bool RequiresByteOrder() const override { return type()->RequiresByteOrder(); } bool RequiresByteOrder() const override { return type()->RequiresByteOrder(); }
bool RequiresAnalyzerContext() const override; bool RequiresAnalyzerContext() const override;
protected: protected:
void GenFieldEnd(Output* out, Env* env, const DataPtr& begin) override; void GenFieldEnd(Output* out, Env* env, const DataPtr& begin) override;
bool GenBoundaryCheck(Output* out_cc, Env* env) override; bool GenBoundaryCheck(Output* out_cc, Env* env) override;
bool DoTraverse(DataDepVisitor* visitor) override; bool DoTraverse(DataDepVisitor* visitor) override;
}; };
enum PaddingType enum PaddingType { PAD_BY_LENGTH, PAD_TO_OFFSET, PAD_TO_NEXT_WORD };
{
PAD_BY_LENGTH,
PAD_TO_OFFSET,
PAD_TO_NEXT_WORD
};
class RecordPaddingField : public RecordField class RecordPaddingField : public RecordField {
{
public: public:
RecordPaddingField(ID* id, PaddingType ptype, Expr* expr); RecordPaddingField(ID* id, PaddingType ptype, Expr* expr);
~RecordPaddingField() override; ~RecordPaddingField() override;
void Prepare(Env* env) override; void Prepare(Env* env) override;
void GenPubDecls(Output* out, Env* env) override void GenPubDecls(Output* out, Env* env) override { /* nothing */
{ /* nothing */ }
} void GenPrivDecls(Output* out, Env* env) override { /* nothing */
void GenPrivDecls(Output* out, Env* env) override }
{ /* nothing */
}
void GenInitCode(Output* out, Env* env) override void GenInitCode(Output* out, Env* env) override { /* nothing */
{ /* nothing */ }
} void GenCleanUpCode(Output* out, Env* env) override { /* nothing */
void GenCleanUpCode(Output* out, Env* env) override }
{ /* nothing */ void GenParseCode(Output* out, Env* env) override;
}
void GenParseCode(Output* out, Env* env) override;
int StaticSize(Env* env, int offset) const override; int StaticSize(Env* env, int offset) const override;
bool RequiresByteOrder() const override { return false; } bool RequiresByteOrder() const override { return false; }
protected: protected:
void GenFieldEnd(Output* out, Env* env, const DataPtr& begin) override; void GenFieldEnd(Output* out, Env* env, const DataPtr& begin) override;
bool GenBoundaryCheck(Output* out_cc, Env* env) override; bool GenBoundaryCheck(Output* out_cc, Env* env) override;
bool DoTraverse(DataDepVisitor* visitor) override; bool DoTraverse(DataDepVisitor* visitor) override;
private: private:
PaddingType ptype_; PaddingType ptype_;
Expr* expr_; Expr* expr_;
int wordsize_; int wordsize_;
}; };
#endif // pac_record_h #endif // pac_record_h

View file

@ -9,145 +9,124 @@
#include "pac_type.h" #include "pac_type.h"
#include "pac_typedecl.h" #include "pac_typedecl.h"
namespace namespace {
{
Decl* find_decl(const ID* id) Decl* find_decl(const ID* id) {
{ Decl* decl = Decl::LookUpDecl(id);
Decl* decl = Decl::LookUpDecl(id); if ( ! decl ) {
if ( ! decl ) throw Exception(id, strfmt("cannot find declaration for %s", id->Name()));
{ }
throw Exception(id, strfmt("cannot find declaration for %s", id->Name()));
}
return decl; return decl;
} }
} } // namespace
Decl* ProcessTypeRedef(const ID* id, FieldList* fieldlist) Decl* ProcessTypeRedef(const ID* id, FieldList* fieldlist) {
{ Decl* decl = find_decl(id);
Decl* decl = find_decl(id);
if ( decl->decl_type() != Decl::TYPE ) if ( decl->decl_type() != Decl::TYPE ) {
{ throw Exception(id, strfmt("not a type declaration: %s", id->Name()));
throw Exception(id, strfmt("not a type declaration: %s", id->Name())); }
}
TypeDecl* type_decl = static_cast<TypeDecl*>(decl); TypeDecl* type_decl = static_cast<TypeDecl*>(decl);
ASSERT(type_decl); ASSERT(type_decl);
Type* type = type_decl->type(); Type* type = type_decl->type();
foreach (i, FieldList, fieldlist) foreach (i, FieldList, fieldlist) {
{ Field* f = *i;
Field* f = *i;
// One cannot change data layout in 'redef'. // One cannot change data layout in 'redef'.
// Only 'let' or 'action' can be added // Only 'let' or 'action' can be added
if ( f->tof() == LET_FIELD || f->tof() == WITHINPUT_FIELD ) if ( f->tof() == LET_FIELD || f->tof() == WITHINPUT_FIELD ) {
{ type->AddField(f);
type->AddField(f); }
} else if ( f->tof() == RECORD_FIELD || f->tof() == PADDING_FIELD ) {
else if ( f->tof() == RECORD_FIELD || f->tof() == PADDING_FIELD ) throw Exception(f, "cannot change data layout in redef");
{ }
throw Exception(f, "cannot change data layout in redef"); else if ( f->tof() == CASE_FIELD ) {
} throw Exception(f, "use 'redef case' adding cases");
else if ( f->tof() == CASE_FIELD ) }
{ }
throw Exception(f, "use 'redef case' adding cases");
}
}
return decl; return decl;
} }
Decl* ProcessCaseTypeRedef(const ID* id, CaseFieldList* casefieldlist) Decl* ProcessCaseTypeRedef(const ID* id, CaseFieldList* casefieldlist) {
{ Decl* decl = find_decl(id);
Decl* decl = find_decl(id);
if ( decl->decl_type() != Decl::TYPE ) if ( decl->decl_type() != Decl::TYPE ) {
{ throw Exception(id, strfmt("not a type declaration: %s", id->Name()));
throw Exception(id, strfmt("not a type declaration: %s", id->Name())); }
}
TypeDecl* type_decl = static_cast<TypeDecl*>(decl); TypeDecl* type_decl = static_cast<TypeDecl*>(decl);
ASSERT(type_decl); ASSERT(type_decl);
Type* type = type_decl->type(); Type* type = type_decl->type();
if ( type->tot() != Type::CASE ) if ( type->tot() != Type::CASE ) {
{ throw Exception(id, strfmt("not a case type: %s", id->Name()));
throw Exception(id, strfmt("not a case type: %s", id->Name())); }
}
CaseType* casetype = static_cast<CaseType*>(type); CaseType* casetype = static_cast<CaseType*>(type);
ASSERT(casetype); ASSERT(casetype);
foreach (i, CaseFieldList, casefieldlist) foreach (i, CaseFieldList, casefieldlist) {
{ CaseField* f = *i;
CaseField* f = *i; casetype->AddCaseField(f);
casetype->AddCaseField(f); }
}
return decl; return decl;
} }
Decl* ProcessCaseExprRedef(const ID* id, CaseExprList* caseexprlist) Decl* ProcessCaseExprRedef(const ID* id, CaseExprList* caseexprlist) {
{ Decl* decl = find_decl(id);
Decl* decl = find_decl(id);
if ( decl->decl_type() != Decl::FUNC ) if ( decl->decl_type() != Decl::FUNC ) {
{ throw Exception(id, strfmt("not a function declaration: %s", id->Name()));
throw Exception(id, strfmt("not a function declaration: %s", id->Name())); }
}
FuncDecl* func_decl = static_cast<FuncDecl*>(decl); FuncDecl* func_decl = static_cast<FuncDecl*>(decl);
ASSERT(func_decl); ASSERT(func_decl);
Expr* expr = func_decl->function()->expr(); Expr* expr = func_decl->function()->expr();
if ( ! expr || expr->expr_type() != Expr::EXPR_CASE ) if ( ! expr || expr->expr_type() != Expr::EXPR_CASE ) {
{ throw Exception(id, strfmt("function not defined by a case expression: %s", id->Name()));
throw Exception(id, strfmt("function not defined by a case expression: %s", id->Name())); }
}
foreach (i, CaseExprList, caseexprlist) foreach (i, CaseExprList, caseexprlist) {
{ CaseExpr* e = *i;
CaseExpr* e = *i; expr->AddCaseExpr(e);
expr->AddCaseExpr(e); }
}
return decl; return decl;
} }
Decl* ProcessAnalyzerRedef(const ID* id, Decl::DeclType decl_type, AnalyzerElementList* elements) Decl* ProcessAnalyzerRedef(const ID* id, Decl::DeclType decl_type, AnalyzerElementList* elements) {
{ Decl* decl = find_decl(id);
Decl* decl = find_decl(id);
if ( decl->decl_type() != decl_type ) if ( decl->decl_type() != decl_type ) {
{ throw Exception(id, strfmt("not a connection/flow declaration: %s", id->Name()));
throw Exception(id, strfmt("not a connection/flow declaration: %s", id->Name())); }
}
AnalyzerDecl* analyzer_decl = static_cast<AnalyzerDecl*>(decl); AnalyzerDecl* analyzer_decl = static_cast<AnalyzerDecl*>(decl);
ASSERT(analyzer_decl); ASSERT(analyzer_decl);
analyzer_decl->AddElements(elements); analyzer_decl->AddElements(elements);
return decl; return decl;
} }
Decl* ProcessTypeAttrRedef(const ID* id, AttrList* attrlist) Decl* ProcessTypeAttrRedef(const ID* id, AttrList* attrlist) {
{ Decl* decl = find_decl(id);
Decl* decl = find_decl(id);
if ( decl->decl_type() != Decl::TYPE ) if ( decl->decl_type() != Decl::TYPE ) {
{ throw Exception(id, strfmt("not a type declaration: %s", id->Name()));
throw Exception(id, strfmt("not a type declaration: %s", id->Name())); }
}
TypeDecl* type_decl = static_cast<TypeDecl*>(decl); TypeDecl* type_decl = static_cast<TypeDecl*>(decl);
ASSERT(type_decl); ASSERT(type_decl);
type_decl->AddAttrs(attrlist); type_decl->AddAttrs(attrlist);
return decl; return decl;
} }

View file

@ -9,71 +9,55 @@
const char* RegEx::kREMatcherType = "RegExMatcher"; const char* RegEx::kREMatcherType = "RegExMatcher";
const char* RegEx::kMatchPrefix = "MatchPrefix"; const char* RegEx::kMatchPrefix = "MatchPrefix";
string escape_char(const string& s) string escape_char(const string& s) {
{ char* buf = new char[s.length() * 2 + 1];
char* buf = new char[s.length() * 2 + 1]; int j = 0;
int j = 0; for ( int i = 0; i < (int)s.length(); ++i ) {
for ( int i = 0; i < (int)s.length(); ++i ) if ( s[i] == '\\' ) {
{ if ( i + 1 < (int)s.length() ) {
if ( s[i] == '\\' ) buf[j++] = '\\';
{ if ( s[i + 1] == '/' )
if ( i + 1 < (int)s.length() ) buf[j - 1] = s[++i];
{ else if ( s[i + 1] == '/' || s[i + 1] == '\\' || s[i + 1] == '"' )
buf[j++] = '\\'; buf[j++] = s[++i];
if ( s[i + 1] == '/' ) else
buf[j - 1] = s[++i]; buf[j++] = '\\';
else if ( s[i + 1] == '/' || s[i + 1] == '\\' || s[i + 1] == '"' ) }
buf[j++] = s[++i]; }
else else if ( s[i] == '"' ) {
buf[j++] = '\\'; buf[j++] = '\\';
} buf[j++] = '"';
} }
else if ( s[i] == '"' ) else {
{ buf[j++] = s[i];
buf[j++] = '\\'; }
buf[j++] = '"'; }
}
else
{
buf[j++] = s[i];
}
}
buf[j++] = '\0'; buf[j++] = '\0';
string rval = buf; string rval = buf;
delete[] buf; delete[] buf;
return rval; return rval;
} }
RegEx::RegEx(const string& s) RegEx::RegEx(const string& s) {
{ str_ = escape_char(s);
str_ = escape_char(s); string prefix = strfmt("%s_re_", current_decl_id->Name());
string prefix = strfmt("%s_re_", current_decl_id->Name()); matcher_id_ = ID::NewAnonymousID(prefix);
matcher_id_ = ID::NewAnonymousID(prefix); decl_ = new RegExDecl(this);
decl_ = new RegExDecl(this); }
}
RegEx::~RegEx() { } RegEx::~RegEx() {}
RegExDecl::RegExDecl(RegEx* regex) : Decl(regex->matcher_id(), REGEX) RegExDecl::RegExDecl(RegEx* regex) : Decl(regex->matcher_id(), REGEX) { regex_ = regex; }
{
regex_ = regex;
}
void RegExDecl::Prepare() void RegExDecl::Prepare() { global_env()->AddID(id(), GLOBAL_VAR, extern_type_re_matcher); }
{
global_env()->AddID(id(), GLOBAL_VAR, extern_type_re_matcher);
}
void RegExDecl::GenForwardDeclaration(Output* out_h) void RegExDecl::GenForwardDeclaration(Output* out_h) {
{ out_h->println("extern %s %s;\n", RegEx::kREMatcherType, global_env()->LValue(regex_->matcher_id()));
out_h->println("extern %s %s;\n", RegEx::kREMatcherType, }
global_env()->LValue(regex_->matcher_id()));
}
void RegExDecl::GenCode(Output* out_h, Output* out_cc) void RegExDecl::GenCode(Output* out_h, Output* out_cc) {
{ out_cc->println("%s %s(\"%s\");\n", RegEx::kREMatcherType, global_env()->LValue(regex_->matcher_id()),
out_cc->println("%s %s(\"%s\");\n", RegEx::kREMatcherType, regex_->str().c_str());
global_env()->LValue(regex_->matcher_id()), regex_->str().c_str()); }
}

View file

@ -6,36 +6,34 @@
class RegExDecl; class RegExDecl;
class RegEx : public Object class RegEx : public Object {
{
public: public:
RegEx(const string& str); RegEx(const string& str);
~RegEx(); ~RegEx();
const string& str() const { return str_; } const string& str() const { return str_; }
ID* matcher_id() const { return matcher_id_; } ID* matcher_id() const { return matcher_id_; }
private: private:
string str_; string str_;
ID* matcher_id_; ID* matcher_id_;
RegExDecl* decl_; RegExDecl* decl_;
public: public:
static const char* kREMatcherType; static const char* kREMatcherType;
static const char* kMatchPrefix; static const char* kMatchPrefix;
}; };
class RegExDecl : public Decl class RegExDecl : public Decl {
{
public: public:
RegExDecl(RegEx* regex); RegExDecl(RegEx* regex);
void Prepare() override; void Prepare() override;
void GenForwardDeclaration(Output* out_h) override; void GenForwardDeclaration(Output* out_h) override;
void GenCode(Output* out_h, Output* out_cc) override; void GenCode(Output* out_h, Output* out_cc) override;
private: private:
RegEx* regex_; RegEx* regex_;
}; };
#endif // pac_regex_h #endif // pac_regex_h

View file

@ -4,23 +4,20 @@
#include "pac_output.h" #include "pac_output.h"
#include "pac_type.h" #include "pac_type.h"
void StateVar::GenDecl(Output* out_h, Env* env) void StateVar::GenDecl(Output* out_h, Env* env) {
{ out_h->println("%s %s;", type_->DataTypeStr().c_str(), env->LValue(id_));
out_h->println("%s %s;", type_->DataTypeStr().c_str(), env->LValue(id_)); }
}
void StateVar::GenAccessFunction(Output* out_h, Env* env) void StateVar::GenAccessFunction(Output* out_h, Env* env) {
{ out_h->println("%s %s const { return %s; }", type_->DataTypeConstRefStr().c_str(), env->RValue(id_),
out_h->println("%s %s const { return %s; }", type_->DataTypeConstRefStr().c_str(), env->LValue(id_));
env->RValue(id_), env->LValue(id_)); }
}
void StateVar::GenSetFunction(Output* out_h, Env* env) void StateVar::GenSetFunction(Output* out_h, Env* env) {
{ out_h->println("void %s(%s x) { %s = x; }", set_function(id_).c_str(), type_->DataTypeConstRefStr().c_str(),
out_h->println("void %s(%s x) { %s = x; }", set_function(id_).c_str(), env->LValue(id_));
type_->DataTypeConstRefStr().c_str(), env->LValue(id_)); }
}
void StateVar::GenInitCode(Output* out_cc, Env* env) { } void StateVar::GenInitCode(Output* out_cc, Env* env) {}
void StateVar::GenCleanUpCode(Output* out_cc, Env* env) { } void StateVar::GenCleanUpCode(Output* out_cc, Env* env) {}

View file

@ -5,23 +5,22 @@
#include "pac_common.h" #include "pac_common.h"
class StateVar class StateVar {
{
public: public:
StateVar(ID* id, Type* type) : id_(id), type_(type) { } StateVar(ID* id, Type* type) : id_(id), type_(type) {}
const ID* id() const { return id_; } const ID* id() const { return id_; }
Type* type() const { return type_; } Type* type() const { return type_; }
void GenDecl(Output* out_h, Env* env); void GenDecl(Output* out_h, Env* env);
void GenAccessFunction(Output* out_h, Env* env); void GenAccessFunction(Output* out_h, Env* env);
void GenSetFunction(Output* out_h, Env* env); void GenSetFunction(Output* out_h, Env* env);
void GenInitCode(Output* out_cc, Env* env); void GenInitCode(Output* out_cc, Env* env);
void GenCleanUpCode(Output* out_cc, Env* env); void GenCleanUpCode(Output* out_cc, Env* env);
private: private:
ID* id_; ID* id_;
Type* type_; Type* type_;
}; };
#endif // pac_state_h #endif // pac_state_h

View file

@ -15,388 +15,293 @@
const char* StringType::kStringTypeName = "bytestring"; const char* StringType::kStringTypeName = "bytestring";
const char* StringType::kConstStringTypeName = "const_bytestring"; const char* StringType::kConstStringTypeName = "const_bytestring";
StringType::StringType(StringTypeEnum anystr) StringType::StringType(StringTypeEnum anystr) : Type(STRING), type_(ANYSTR), str_(nullptr), regex_(nullptr) {
: Type(STRING), type_(ANYSTR), str_(nullptr), regex_(nullptr) ASSERT(anystr == ANYSTR);
{ init();
ASSERT(anystr == ANYSTR); }
init();
}
StringType::StringType(ConstString* str) : Type(STRING), type_(CSTR), str_(str), regex_(nullptr) StringType::StringType(ConstString* str) : Type(STRING), type_(CSTR), str_(str), regex_(nullptr) { init(); }
{
init();
}
StringType::StringType(RegEx* regex) : Type(STRING), type_(REGEX), str_(nullptr), regex_(regex) StringType::StringType(RegEx* regex) : Type(STRING), type_(REGEX), str_(nullptr), regex_(regex) {
{ ASSERT(regex_);
ASSERT(regex_); init();
init(); }
}
void StringType::init() void StringType::init() {
{ string_length_var_field_ = nullptr;
string_length_var_field_ = nullptr; elem_datatype_ = new BuiltInType(BuiltInType::UINT8);
elem_datatype_ = new BuiltInType(BuiltInType::UINT8); }
}
StringType::~StringType() StringType::~StringType() {
{ // TODO: Unref for Objects
// TODO: Unref for Objects // Question: why Unref?
// Question: why Unref? //
// // Unref(str_);
// Unref(str_); // Unref(regex_);
// Unref(regex_);
delete string_length_var_field_; delete string_length_var_field_;
delete elem_datatype_; delete elem_datatype_;
} }
Type* StringType::DoClone() const Type* StringType::DoClone() const {
{ StringType* clone;
StringType* clone;
switch ( type_ ) switch ( type_ ) {
{ case ANYSTR: clone = new StringType(ANYSTR); break;
case ANYSTR: case CSTR: clone = new StringType(str_); break;
clone = new StringType(ANYSTR); case REGEX: clone = new StringType(regex_); break;
break; default: ASSERT(0); return nullptr;
case CSTR: }
clone = new StringType(str_);
break;
case REGEX:
clone = new StringType(regex_);
break;
default:
ASSERT(0);
return nullptr;
}
return clone; return clone;
} }
bool StringType::DefineValueVar() const bool StringType::DefineValueVar() const { return true; }
{
return true;
}
string StringType::DataTypeStr() const string StringType::DataTypeStr() const { return strfmt("%s", persistent() ? kStringTypeName : kConstStringTypeName); }
{
return strfmt("%s", persistent() ? kStringTypeName : kConstStringTypeName);
}
Type* StringType::ElementDataType() const Type* StringType::ElementDataType() const { return elem_datatype_; }
{
return elem_datatype_;
}
void StringType::ProcessAttr(Attr* a) void StringType::ProcessAttr(Attr* a) {
{ Type::ProcessAttr(a);
Type::ProcessAttr(a);
switch ( a->type() ) switch ( a->type() ) {
{ case ATTR_CHUNKED: {
case ATTR_CHUNKED: if ( type_ != ANYSTR ) {
{ throw Exception(a,
if ( type_ != ANYSTR ) "&chunked can be applied"
{ " to only type bytestring");
throw Exception(a, "&chunked can be applied" }
" to only type bytestring"); attr_chunked_ = true;
} SetBoundaryChecked();
attr_chunked_ = true; } break;
SetBoundaryChecked();
}
break;
case ATTR_RESTOFDATA: case ATTR_RESTOFDATA: {
{ if ( type_ != ANYSTR ) {
if ( type_ != ANYSTR ) throw Exception(a,
{ "&restofdata can be applied"
throw Exception(a, "&restofdata can be applied" " to only type bytestring");
" to only type bytestring"); }
} attr_restofdata_ = true;
attr_restofdata_ = true; // As the string automatically extends to the end of
// As the string automatically extends to the end of // data, we do not have to check boundary.
// data, we do not have to check boundary. SetBoundaryChecked();
SetBoundaryChecked(); } break;
}
break;
case ATTR_RESTOFFLOW: case ATTR_RESTOFFLOW: {
{ if ( type_ != ANYSTR ) {
if ( type_ != ANYSTR ) throw Exception(a,
{ "&restofflow can be applied"
throw Exception(a, "&restofflow can be applied" " to only type bytestring");
" to only type bytestring"); }
} attr_restofflow_ = true;
attr_restofflow_ = true; // As the string automatically extends to the end of
// As the string automatically extends to the end of // flow, we do not have to check boundary.
// flow, we do not have to check boundary. SetBoundaryChecked();
SetBoundaryChecked(); } break;
}
break;
default: default: break;
break; }
} }
}
void StringType::Prepare(Env* env, int flags) void StringType::Prepare(Env* env, int flags) {
{ if ( (flags & TO_BE_PARSED) && StaticSize(env) < 0 ) {
if ( (flags & TO_BE_PARSED) && StaticSize(env) < 0 ) ID* string_length_var = new ID(strfmt("%s_string_length", value_var() ? value_var()->Name() : "val"));
{ string_length_var_field_ = new TempVarField(string_length_var, extern_type_int->Clone());
ID* string_length_var = new ID( string_length_var_field_->Prepare(env);
strfmt("%s_string_length", value_var() ? value_var()->Name() : "val")); }
string_length_var_field_ = new TempVarField(string_length_var, extern_type_int->Clone()); Type::Prepare(env, flags);
string_length_var_field_->Prepare(env); }
}
Type::Prepare(env, flags);
}
void StringType::GenPubDecls(Output* out_h, Env* env) void StringType::GenPubDecls(Output* out_h, Env* env) { Type::GenPubDecls(out_h, env); }
{
Type::GenPubDecls(out_h, env);
}
void StringType::GenPrivDecls(Output* out_h, Env* env) void StringType::GenPrivDecls(Output* out_h, Env* env) { Type::GenPrivDecls(out_h, env); }
{
Type::GenPrivDecls(out_h, env);
}
void StringType::GenInitCode(Output* out_cc, Env* env) void StringType::GenInitCode(Output* out_cc, Env* env) { Type::GenInitCode(out_cc, env); }
{
Type::GenInitCode(out_cc, env);
}
void StringType::GenCleanUpCode(Output* out_cc, Env* env) void StringType::GenCleanUpCode(Output* out_cc, Env* env) {
{ Type::GenCleanUpCode(out_cc, env);
Type::GenCleanUpCode(out_cc, env); if ( persistent() )
if ( persistent() ) out_cc->println("%s.free();", env->LValue(value_var()));
out_cc->println("%s.free();", env->LValue(value_var())); }
}
void StringType::DoMarkIncrementalInput() void StringType::DoMarkIncrementalInput() {
{ if ( attr_restofflow_ ) {
if ( attr_restofflow_ ) // Do nothing
{ ASSERT(type_ == ANYSTR);
// Do nothing }
ASSERT(type_ == ANYSTR); else {
} Type::DoMarkIncrementalInput();
else }
{ }
Type::DoMarkIncrementalInput();
}
}
int StringType::StaticSize(Env* env) const int StringType::StaticSize(Env* env) const {
{ switch ( type_ ) {
switch ( type_ ) case CSTR:
{ // Use length of the unescaped string
case CSTR: return str_->unescaped().length();
// Use length of the unescaped string case REGEX:
return str_->unescaped().length(); // TODO: static size for a regular expression?
case REGEX: case ANYSTR: return -1;
// TODO: static size for a regular expression?
case ANYSTR:
return -1;
default: default: ASSERT(0); return -1;
ASSERT(0); }
return -1; }
}
}
const ID* StringType::string_length_var() const const ID* StringType::string_length_var() const {
{ return string_length_var_field_ ? string_length_var_field_->id() : nullptr;
return string_length_var_field_ ? string_length_var_field_->id() : nullptr; }
}
void StringType::GenDynamicSize(Output* out_cc, Env* env, const DataPtr& data) void StringType::GenDynamicSize(Output* out_cc, Env* env, const DataPtr& data) {
{ ASSERT(StaticSize(env) < 0);
ASSERT(StaticSize(env) < 0); DEBUG_MSG("Generating dynamic size for string `%s'\n", value_var()->Name());
DEBUG_MSG("Generating dynamic size for string `%s'\n", value_var()->Name());
if ( env->Evaluated(string_length_var()) ) if ( env->Evaluated(string_length_var()) )
return; return;
string_length_var_field_->GenTempDecls(out_cc, env); string_length_var_field_->GenTempDecls(out_cc, env);
switch ( type_ ) switch ( type_ ) {
{ case ANYSTR: GenDynamicSizeAnyStr(out_cc, env, data); break;
case ANYSTR: case CSTR: ASSERT(0); break;
GenDynamicSizeAnyStr(out_cc, env, data); case REGEX:
break; // TODO: static size for a regular expression?
case CSTR: GenDynamicSizeRegEx(out_cc, env, data);
ASSERT(0); break;
break; }
case REGEX:
// TODO: static size for a regular expression?
GenDynamicSizeRegEx(out_cc, env, data);
break;
}
if ( ! incremental_input() && AddSizeVar(out_cc, env) ) if ( ! incremental_input() && AddSizeVar(out_cc, env) ) {
{ out_cc->println("%s = %s;", env->LValue(size_var()), env->RValue(string_length_var()));
out_cc->println("%s = %s;", env->LValue(size_var()), env->RValue(string_length_var())); env->SetEvaluated(size_var());
env->SetEvaluated(size_var()); }
} }
}
string StringType::GenStringSize(Output* out_cc, Env* env, const DataPtr& data) string StringType::GenStringSize(Output* out_cc, Env* env, const DataPtr& data) {
{ int static_size = StaticSize(env);
int static_size = StaticSize(env); if ( static_size >= 0 )
if ( static_size >= 0 ) return strfmt("%d", static_size);
return strfmt("%d", static_size); GenDynamicSize(out_cc, env, data);
GenDynamicSize(out_cc, env, data); return env->RValue(string_length_var());
return env->RValue(string_length_var()); }
}
void StringType::DoGenParseCode(Output* out_cc, Env* env, const DataPtr& data, int flags) void StringType::DoGenParseCode(Output* out_cc, Env* env, const DataPtr& data, int flags) {
{ string str_size = GenStringSize(out_cc, env, data);
string str_size = GenStringSize(out_cc, env, data);
// Generate additional checking // Generate additional checking
switch ( type_ ) switch ( type_ ) {
{ case CSTR: GenCheckingCStr(out_cc, env, data, str_size); break;
case CSTR: case REGEX:
GenCheckingCStr(out_cc, env, data, str_size); case ANYSTR: break;
break; }
case REGEX:
case ANYSTR:
break;
}
if ( ! anonymous_value_var() ) if ( ! anonymous_value_var() ) {
{ // Set the value variable
// Set the value variable
int len; int len;
if ( type_ == ANYSTR && attr_length_expr_ && attr_length_expr_->ConstFold(env, &len) ) if ( type_ == ANYSTR && attr_length_expr_ && attr_length_expr_->ConstFold(env, &len) ) {
{ // can check for a negative length now
// can check for a negative length now if ( len < 0 )
if ( len < 0 ) throw Exception(this, "negative &length on string");
throw Exception(this, "negative &length on string"); }
} else {
else out_cc->println("// check for negative sizes");
{ out_cc->println("if ( %s < 0 )", str_size.c_str());
out_cc->println("// check for negative sizes"); out_cc->println("throw binpac::ExceptionInvalidStringLength(\"%s\", %s);", Location(), str_size.c_str());
out_cc->println("if ( %s < 0 )", str_size.c_str()); }
out_cc->println("throw binpac::ExceptionInvalidStringLength(\"%s\", %s);", Location(),
str_size.c_str());
}
out_cc->println("%s.init(%s, %s);", env->LValue(value_var()), data.ptr_expr(), out_cc->println("%s.init(%s, %s);", env->LValue(value_var()), data.ptr_expr(), str_size.c_str());
str_size.c_str()); }
}
if ( parsing_complete_var() ) if ( parsing_complete_var() ) {
{ out_cc->println("%s = true;", env->LValue(parsing_complete_var()));
out_cc->println("%s = true;", env->LValue(parsing_complete_var())); }
} }
}
void StringType::GenStringMismatch(Output* out_cc, Env* env, const DataPtr& data, string pattern) void StringType::GenStringMismatch(Output* out_cc, Env* env, const DataPtr& data, string pattern) {
{ string tmp =
string tmp = strfmt("string((const char *) (%s), (const char *) %s).c_str()", data.ptr_expr(), strfmt("string((const char *) (%s), (const char *) %s).c_str()", data.ptr_expr(), env->RValue(end_of_data));
env->RValue(end_of_data)); out_cc->println("throw binpac::ExceptionStringMismatch(\"%s\", %s, %s);", Location(), pattern.c_str(), tmp.c_str());
out_cc->println("throw binpac::ExceptionStringMismatch(\"%s\", %s, %s);", Location(), }
pattern.c_str(), tmp.c_str());
}
void StringType::GenCheckingCStr(Output* out_cc, Env* env, const DataPtr& data, void StringType::GenCheckingCStr(Output* out_cc, Env* env, const DataPtr& data, const string& str_size) {
const string& str_size) // TODO: extend it for dynamic strings
{ ASSERT(type_ == CSTR);
// TODO: extend it for dynamic strings
ASSERT(type_ == CSTR);
GenBoundaryCheck(out_cc, env, data); GenBoundaryCheck(out_cc, env, data);
string str_val = str_->str(); string str_val = str_->str();
// Compare the string and report error on mismatch // Compare the string and report error on mismatch
out_cc->println("if ( memcmp(%s, %s, %s) != 0 )", data.ptr_expr(), str_val.c_str(), out_cc->println("if ( memcmp(%s, %s, %s) != 0 )", data.ptr_expr(), str_val.c_str(), str_size.c_str());
str_size.c_str()); out_cc->inc_indent();
out_cc->inc_indent(); out_cc->println("{");
out_cc->println("{"); GenStringMismatch(out_cc, env, data, str_val);
GenStringMismatch(out_cc, env, data, str_val); out_cc->println("}");
out_cc->println("}"); out_cc->dec_indent();
out_cc->dec_indent(); }
}
void StringType::GenDynamicSizeRegEx(Output* out_cc, Env* env, const DataPtr& data) void StringType::GenDynamicSizeRegEx(Output* out_cc, Env* env, const DataPtr& data) {
{ // string_length_var =
// string_length_var = // matcher.match_prefix(
// matcher.match_prefix( // begin,
// begin, // end);
// end);
out_cc->println("%s = ", env->LValue(string_length_var())); out_cc->println("%s = ", env->LValue(string_length_var()));
out_cc->inc_indent(); out_cc->inc_indent();
out_cc->println("%s.%s(", env->RValue(regex_->matcher_id()), RegEx::kMatchPrefix); out_cc->println("%s.%s(", env->RValue(regex_->matcher_id()), RegEx::kMatchPrefix);
out_cc->inc_indent(); out_cc->inc_indent();
out_cc->println("%s,", data.ptr_expr()); out_cc->println("%s,", data.ptr_expr());
out_cc->println("%s - %s);", env->RValue(end_of_data), data.ptr_expr()); out_cc->println("%s - %s);", env->RValue(end_of_data), data.ptr_expr());
out_cc->dec_indent(); out_cc->dec_indent();
out_cc->dec_indent(); out_cc->dec_indent();
env->SetEvaluated(string_length_var()); env->SetEvaluated(string_length_var());
out_cc->println("if ( %s < 0 )", env->RValue(string_length_var())); out_cc->println("if ( %s < 0 )", env->RValue(string_length_var()));
out_cc->inc_indent(); out_cc->inc_indent();
out_cc->println("{"); out_cc->println("{");
string tmp = strfmt("\"%s\"", regex_->str().c_str()); string tmp = strfmt("\"%s\"", regex_->str().c_str());
GenStringMismatch(out_cc, env, data, tmp); GenStringMismatch(out_cc, env, data, tmp);
out_cc->println("}"); out_cc->println("}");
out_cc->dec_indent(); out_cc->dec_indent();
} }
void StringType::GenDynamicSizeAnyStr(Output* out_cc, Env* env, const DataPtr& data) void StringType::GenDynamicSizeAnyStr(Output* out_cc, Env* env, const DataPtr& data) {
{ ASSERT(type_ == ANYSTR);
ASSERT(type_ == ANYSTR);
if ( attr_restofdata_ || attr_oneline_ ) if ( attr_restofdata_ || attr_oneline_ ) {
{ out_cc->println("%s = (%s) - (%s);", env->LValue(string_length_var()), env->RValue(end_of_data),
out_cc->println("%s = (%s) - (%s);", env->LValue(string_length_var()), data.ptr_expr());
env->RValue(end_of_data), data.ptr_expr()); }
} else if ( attr_restofflow_ ) {
else if ( attr_restofflow_ ) out_cc->println("%s = (%s) - (%s);", env->LValue(string_length_var()), env->RValue(end_of_data),
{ data.ptr_expr());
out_cc->println("%s = (%s) - (%s);", env->LValue(string_length_var()), }
env->RValue(end_of_data), data.ptr_expr()); else if ( attr_length_expr_ ) {
} out_cc->println("%s = %s;", env->LValue(string_length_var()), attr_length_expr_->EvalExpr(out_cc, env));
else if ( attr_length_expr_ ) }
{ else {
out_cc->println("%s = %s;", env->LValue(string_length_var()), throw Exception(this, "cannot determine length of bytestring");
attr_length_expr_->EvalExpr(out_cc, env)); }
}
else
{
throw Exception(this, "cannot determine length of bytestring");
}
env->SetEvaluated(string_length_var()); env->SetEvaluated(string_length_var());
} }
bool StringType::DoTraverse(DataDepVisitor* visitor) bool StringType::DoTraverse(DataDepVisitor* visitor) {
{ if ( ! Type::DoTraverse(visitor) )
if ( ! Type::DoTraverse(visitor) ) return false;
return false;
switch ( type_ ) switch ( type_ ) {
{ case ANYSTR:
case ANYSTR: case CSTR:
case CSTR: case REGEX: break;
case REGEX: }
break;
}
return true; return true;
} }
void StringType::static_init() void StringType::static_init() { Type::AddPredefinedType("bytestring", new StringType(ANYSTR)); }
{
Type::AddPredefinedType("bytestring", new StringType(ANYSTR));
}

View file

@ -4,83 +4,77 @@
#include "pac_type.h" #include "pac_type.h"
// TODO: question: shall we merge it with ArrayType? // TODO: question: shall we merge it with ArrayType?
class StringType : public Type class StringType : public Type {
{
public: public:
enum StringTypeEnum enum StringTypeEnum { CSTR, REGEX, ANYSTR };
{
CSTR,
REGEX,
ANYSTR
};
explicit StringType(StringTypeEnum anystr); explicit StringType(StringTypeEnum anystr);
explicit StringType(ConstString* str); explicit StringType(ConstString* str);
explicit StringType(RegEx* regex); explicit StringType(RegEx* regex);
~StringType() override; ~StringType() override;
bool DefineValueVar() const override; bool DefineValueVar() const override;
string DataTypeStr() const override; string DataTypeStr() const override;
string DefaultValue() const override { return "0"; } string DefaultValue() const override { return "0"; }
Type* ElementDataType() const override; Type* ElementDataType() const override;
void Prepare(Env* env, int flags) override; void Prepare(Env* env, int flags) override;
void GenPubDecls(Output* out, Env* env) override; void GenPubDecls(Output* out, Env* env) override;
void GenPrivDecls(Output* out, Env* env) override; void GenPrivDecls(Output* out, Env* env) override;
void GenInitCode(Output* out, Env* env) override; void GenInitCode(Output* out, Env* env) override;
void GenCleanUpCode(Output* out, Env* env) override; void GenCleanUpCode(Output* out, Env* env) override;
void DoMarkIncrementalInput() override; void DoMarkIncrementalInput() override;
int StaticSize(Env* env) const override; int StaticSize(Env* env) const override;
bool IsPointerType() const override { return false; } bool IsPointerType() const override { return false; }
void ProcessAttr(Attr* a) override; void ProcessAttr(Attr* a) override;
protected: protected:
void init(); void init();
// Generate computation of size of the string and returns the string // Generate computation of size of the string and returns the string
// representing a constant integer or name of the length variable. // representing a constant integer or name of the length variable.
string GenStringSize(Output* out_cc, Env* env, const DataPtr& data); string GenStringSize(Output* out_cc, Env* env, const DataPtr& data);
// Generate a string mismatch exception // Generate a string mismatch exception
void GenStringMismatch(Output* out_cc, Env* env, const DataPtr& data, string pattern); void GenStringMismatch(Output* out_cc, Env* env, const DataPtr& data, string pattern);
void DoGenParseCode(Output* out, Env* env, const DataPtr& data, int flags) override; void DoGenParseCode(Output* out, Env* env, const DataPtr& data, int flags) override;
void GenCheckingCStr(Output* out, Env* env, const DataPtr& data, const string& str_size); void GenCheckingCStr(Output* out, Env* env, const DataPtr& data, const string& str_size);
void GenDynamicSize(Output* out, Env* env, const DataPtr& data) override; void GenDynamicSize(Output* out, Env* env, const DataPtr& data) override;
void GenDynamicSizeAnyStr(Output* out_cc, Env* env, const DataPtr& data); void GenDynamicSizeAnyStr(Output* out_cc, Env* env, const DataPtr& data);
void GenDynamicSizeRegEx(Output* out_cc, Env* env, const DataPtr& data); void GenDynamicSizeRegEx(Output* out_cc, Env* env, const DataPtr& data);
Type* DoClone() const override; Type* DoClone() const override;
// TODO: insensitive towards byte order till we support unicode // TODO: insensitive towards byte order till we support unicode
bool ByteOrderSensitive() const override { return false; } bool ByteOrderSensitive() const override { return false; }
protected: protected:
bool DoTraverse(DataDepVisitor* visitor) override; bool DoTraverse(DataDepVisitor* visitor) override;
private: private:
const ID* string_length_var() const; const ID* string_length_var() const;
StringTypeEnum type_; StringTypeEnum type_;
ConstString* str_; ConstString* str_;
RegEx* regex_; RegEx* regex_;
Field* string_length_var_field_; Field* string_length_var_field_;
Type* elem_datatype_; Type* elem_datatype_;
public: public:
static void static_init(); static void static_init();
private: private:
static const char* kStringTypeName; static const char* kStringTypeName;
static const char* kConstStringTypeName; static const char* kConstStringTypeName;
}; };
#endif // pac_strtype_h #endif // pac_strtype_h

File diff suppressed because it is too large Load diff

View file

@ -8,304 +8,298 @@ using namespace std;
#include "pac_datadep.h" #include "pac_datadep.h"
#include "pac_dbg.h" #include "pac_dbg.h"
class Type : public Object, public DataDepElement class Type : public Object, public DataDepElement {
{
public: public:
enum TypeType enum TypeType {
{ UNDEF = -1,
UNDEF = -1, EMPTY,
EMPTY, BUILTIN,
BUILTIN, PARAMETERIZED,
PARAMETERIZED, RECORD,
RECORD, CASE,
CASE, ARRAY,
ARRAY, STRING,
STRING, EXTERN,
EXTERN, DUMMY,
DUMMY, };
};
explicit Type(TypeType tot); explicit Type(TypeType tot);
~Type() override; ~Type() override;
Type* Clone() const; Type* Clone() const;
// Type of type // Type of type
TypeType tot() const { return tot_; } TypeType tot() const { return tot_; }
//////////////////////////////////////// ////////////////////////////////////////
// Code generation // Code generation
virtual void Prepare(Env* env, int flags); virtual void Prepare(Env* env, int flags);
// Flag(s) for Prepare() // Flag(s) for Prepare()
static const int TO_BE_PARSED = 1; static const int TO_BE_PARSED = 1;
virtual void GenPubDecls(Output* out, Env* env); virtual void GenPubDecls(Output* out, Env* env);
virtual void GenPrivDecls(Output* out, Env* env); virtual void GenPrivDecls(Output* out, Env* env);
virtual void GenInitCode(Output* out, Env* env); virtual void GenInitCode(Output* out, Env* env);
virtual void GenCleanUpCode(Output* out, Env* env); virtual void GenCleanUpCode(Output* out, Env* env);
void GenPreParsing(Output* out, Env* env); void GenPreParsing(Output* out, Env* env);
void GenParseCode(Output* out, Env* env, const DataPtr& data, int flags); void GenParseCode(Output* out, Env* env, const DataPtr& data, int flags);
//////////////////////////////////////// ////////////////////////////////////////
// TODO: organize the various methods below // TODO: organize the various methods below
// The LValue string of the variable defined by the type. // The LValue string of the variable defined by the type.
// For example, if the type defines a record field, the // For example, if the type defines a record field, the
// lvalue is the member variable corresponding to the field; // lvalue is the member variable corresponding to the field;
// if the type appears in a type decl, then the lvalue is the // if the type appears in a type decl, then the lvalue is the
// default value var. // default value var.
// //
const char* lvalue() const { return lvalue_.c_str(); } const char* lvalue() const { return lvalue_.c_str(); }
// The TypeDecl that defined the type. // The TypeDecl that defined the type.
// //
const TypeDecl* type_decl() const { return type_decl_; } const TypeDecl* type_decl() const { return type_decl_; }
void set_type_decl(const TypeDecl* decl, bool declared_as_type); void set_type_decl(const TypeDecl* decl, bool declared_as_type);
// Returns whether the type appears in a type declaration // Returns whether the type appears in a type declaration
// (true) or as type specification of a field (false). // (true) or as type specification of a field (false).
// //
bool declared_as_type() const { return declared_as_type_; } bool declared_as_type() const { return declared_as_type_; }
// The ID of the decl in which the type appear. // The ID of the decl in which the type appear.
// //
const ID* decl_id() const; const ID* decl_id() const;
Env* env() const { return env_; } Env* env() const { return env_; }
string EvalByteOrder(Output* out_cc, Env* env) const; string EvalByteOrder(Output* out_cc, Env* env) const;
virtual string EvalMember(const ID* member_id) const; virtual string EvalMember(const ID* member_id) const;
virtual string EvalElement(const string& array, const string& index) const; virtual string EvalElement(const string& array, const string& index) const;
// The variable defined by the type // The variable defined by the type
const ID* value_var() const { return value_var_; } const ID* value_var() const { return value_var_; }
void set_value_var(const ID* arg_id, int arg_id_type); void set_value_var(const ID* arg_id, int arg_id_type);
bool anonymous_value_var() const { return anonymous_value_var_; } bool anonymous_value_var() const { return anonymous_value_var_; }
const ID* size_var() const; const ID* size_var() const;
// Adds a variable to env to represent the size of this type. // Adds a variable to env to represent the size of this type.
// Returns false if we do not need a size variable (because // Returns false if we do not need a size variable (because
// the type has a static size) or the size variable is already added. // the type has a static size) or the size variable is already added.
bool AddSizeVar(Output* out, Env* env); bool AddSizeVar(Output* out, Env* env);
const ID* parsing_state_var() const; const ID* parsing_state_var() const;
const ID* has_value_var() const; const ID* has_value_var() const;
void AddField(Field* f); void AddField(Field* f);
void AddCheck(Expr* expr) void AddCheck(Expr* expr) { /* TODO */
{ /* TODO */ }
}
virtual bool DefineValueVar() const = 0; virtual bool DefineValueVar() const = 0;
// Returns C++ datatype string // Returns C++ datatype string
virtual string DataTypeStr() const = 0; virtual string DataTypeStr() const = 0;
// Returns const reference of the C++ data type (unless the type // Returns const reference of the C++ data type (unless the type
// is numeric or pointer) // is numeric or pointer)
string DataTypeConstRefStr() const string DataTypeConstRefStr() const {
{ string data_type = DataTypeStr();
string data_type = DataTypeStr(); if ( ! IsPointerType() && ! IsNumericType() )
if ( ! IsPointerType() && ! IsNumericType() ) data_type += " const &";
data_type += " const &"; return data_type;
return data_type; }
}
// Returns a default value for the type // Returns a default value for the type
virtual string DefaultValue() const virtual string DefaultValue() const {
{ ASSERT(0);
ASSERT(0); return "@@@";
return "@@@"; }
}
// Returns the data type of the member field/case // Returns the data type of the member field/case
virtual Type* MemberDataType(const ID* member_id) const; virtual Type* MemberDataType(const ID* member_id) const;
// Returns the data type of the element type of an array // Returns the data type of the element type of an array
virtual Type* ElementDataType() const; virtual Type* ElementDataType() const;
// Whether the type needs clean-up at deallocation. // Whether the type needs clean-up at deallocation.
bool NeedsCleanUp() const; bool NeedsCleanUp() const;
// Whether byte order must be determined before parsing the type. // Whether byte order must be determined before parsing the type.
bool RequiresByteOrder() const; bool RequiresByteOrder() const;
// Whether class of the type requires a parameter of analyzer context. // Whether class of the type requires a parameter of analyzer context.
virtual bool RequiresAnalyzerContext(); virtual bool RequiresAnalyzerContext();
virtual bool IsPointerType() const = 0; virtual bool IsPointerType() const = 0;
virtual bool IsNumericType() const { return false; } virtual bool IsNumericType() const { return false; }
bool IsEmptyType() const; bool IsEmptyType() const;
//////////////////////////////////////// ////////////////////////////////////////
// Attributes // Attributes
virtual void ProcessAttr(Attr* a); virtual void ProcessAttr(Attr* a);
bool attr_chunked() const { return attr_chunked_; } bool attr_chunked() const { return attr_chunked_; }
Expr* attr_byteorder_expr() const { return attr_byteorder_expr_; } Expr* attr_byteorder_expr() const { return attr_byteorder_expr_; }
Expr* attr_if_expr() const { return attr_if_expr_; } Expr* attr_if_expr() const { return attr_if_expr_; }
// TODO: generate the length expression automatically. // TODO: generate the length expression automatically.
Expr* attr_length_expr() const { return attr_length_expr_; } Expr* attr_length_expr() const { return attr_length_expr_; }
bool attr_refcount() const { return attr_refcount_; } bool attr_refcount() const { return attr_refcount_; }
bool attr_transient() const { return attr_transient_; } bool attr_transient() const { return attr_transient_; }
// Whether the value remains valid outside the parse function // Whether the value remains valid outside the parse function
bool persistent() const { return ! attr_transient() && ! attr_chunked(); } bool persistent() const { return ! attr_transient() && ! attr_chunked(); }
void SetUntilCheck(ArrayType* t) { array_until_input_ = t; } void SetUntilCheck(ArrayType* t) { array_until_input_ = t; }
//////////////////////////////////////// ////////////////////////////////////////
// Size and boundary checking // Size and boundary checking
virtual int StaticSize(Env* env) const = 0; virtual int StaticSize(Env* env) const = 0;
string DataSize(Output* out, Env* env, const DataPtr& data); string DataSize(Output* out, Env* env, const DataPtr& data);
bool boundary_checked() const { return boundary_checked_; } bool boundary_checked() const { return boundary_checked_; }
virtual void SetBoundaryChecked() { boundary_checked_ = true; } virtual void SetBoundaryChecked() { boundary_checked_ = true; }
void GenBoundaryCheck(Output* out, Env* env, const DataPtr& data); void GenBoundaryCheck(Output* out, Env* env, const DataPtr& data);
//////////////////////////////////////// ////////////////////////////////////////
// Handling incremental input // Handling incremental input
// //
// There are two ways to handle incremental input: (1) to // There are two ways to handle incremental input: (1) to
// buffer the input before parsing; (2) to parse incrementally. // buffer the input before parsing; (2) to parse incrementally.
// //
// The type must be "bufferable" for (1). While for (2), // The type must be "bufferable" for (1). While for (2),
// each member of the type must be able to handle incremental // each member of the type must be able to handle incremental
// input. // input.
void MarkIncrementalInput(); void MarkIncrementalInput();
virtual void DoMarkIncrementalInput(); virtual void DoMarkIncrementalInput();
// Whether the type may receive incremental input // Whether the type may receive incremental input
bool incremental_input() const { return incremental_input_; } bool incremental_input() const { return incremental_input_; }
// Whether parsing should also be incremental // Whether parsing should also be incremental
bool incremental_parsing() const { return incremental_parsing_; } bool incremental_parsing() const { return incremental_parsing_; }
// Whether we should buffer the input // Whether we should buffer the input
bool buffer_input() const { return buffer_input_; } bool buffer_input() const { return buffer_input_; }
// Whether parsing of the type is completed // Whether parsing of the type is completed
const ID* parsing_complete_var() const; const ID* parsing_complete_var() const;
string parsing_complete(Env* env) const; string parsing_complete(Env* env) const;
// Whether the input is bufferable // Whether the input is bufferable
bool Bufferable() const; bool Bufferable() const;
bool BufferableByLength() const; bool BufferableByLength() const;
bool BufferableByLine() const; bool BufferableByLine() const;
bool BufferableWithLineBreaker() const; bool BufferableWithLineBreaker() const;
Expr* LineBreaker() const; Expr* LineBreaker() const;
enum BufferMode enum BufferMode {
{ NOT_BUFFERABLE,
NOT_BUFFERABLE, BUFFER_NOTHING, // for type "empty"
BUFFER_NOTHING, // for type "empty" BUFFER_BY_LENGTH,
BUFFER_BY_LENGTH, BUFFER_BY_LINE,
BUFFER_BY_LINE, };
}; virtual BufferMode buffer_mode() const;
virtual BufferMode buffer_mode() const;
void GenBufferConfiguration(Output* out, Env* env); void GenBufferConfiguration(Output* out, Env* env);
int InitialBufferLength() const; int InitialBufferLength() const;
protected: protected:
virtual void GenNewInstance(Output* out, Env* env) { } virtual void GenNewInstance(Output* out, Env* env) {}
virtual bool ByteOrderSensitive() const = 0; virtual bool ByteOrderSensitive() const = 0;
bool NeedsBufferingStateVar() const; bool NeedsBufferingStateVar() const;
void GenBufferingLoop(Output* out_cc, Env* env, int flags); void GenBufferingLoop(Output* out_cc, Env* env, int flags);
void GenParseBuffer(Output* out_cc, Env* env, int flags); void GenParseBuffer(Output* out_cc, Env* env, int flags);
void GenParseCode2(Output* out_cc, Env* env, const DataPtr& data, int flags); void GenParseCode2(Output* out_cc, Env* env, const DataPtr& data, int flags);
void GenParseCode3(Output* out_cc, Env* env, const DataPtr& data, int flags); void GenParseCode3(Output* out_cc, Env* env, const DataPtr& data, int flags);
virtual void DoGenParseCode(Output* out, Env* env, const DataPtr& data, int flags) = 0; virtual void DoGenParseCode(Output* out, Env* env, const DataPtr& data, int flags) = 0;
string EvalLengthExpr(Output* out_cc, Env* env); string EvalLengthExpr(Output* out_cc, Env* env);
// Generate code for computing the dynamic size of the type // Generate code for computing the dynamic size of the type
virtual void GenDynamicSize(Output* out, Env* env, const DataPtr& data) = 0; virtual void GenDynamicSize(Output* out, Env* env, const DataPtr& data) = 0;
bool DoTraverse(DataDepVisitor* visitor) override; bool DoTraverse(DataDepVisitor* visitor) override;
virtual Type* DoClone() const = 0; virtual Type* DoClone() const = 0;
protected: protected:
TypeType tot_; TypeType tot_;
const TypeDecl* type_decl_; const TypeDecl* type_decl_;
bool declared_as_type_; bool declared_as_type_;
const ID* type_decl_id_; const ID* type_decl_id_;
Env* env_; Env* env_;
const ID* value_var_; const ID* value_var_;
bool anonymous_value_var_; // whether the ID is anonymous bool anonymous_value_var_; // whether the ID is anonymous
string data_id_str_; string data_id_str_;
int value_var_type_; int value_var_type_;
Field* size_var_field_; Field* size_var_field_;
char* size_expr_; char* size_expr_;
bool boundary_checked_; bool boundary_checked_;
string lvalue_; string lvalue_;
FieldList* fields_; FieldList* fields_;
bool incremental_input_; bool incremental_input_;
bool incremental_parsing_; bool incremental_parsing_;
bool buffer_input_; bool buffer_input_;
// A boolean variable on whether parsing of the type is completed // A boolean variable on whether parsing of the type is completed
Field* parsing_complete_var_field_; Field* parsing_complete_var_field_;
// An integer variable holding the parsing state // An integer variable holding the parsing state
Field* parsing_state_var_field_; Field* parsing_state_var_field_;
Field* buffering_state_var_field_; Field* buffering_state_var_field_;
// The array type with &until($input...) condition, if // The array type with &until($input...) condition, if
// "this" is the element type // "this" is the element type
ArrayType* array_until_input_; ArrayType* array_until_input_;
// A "has_*" member var for fields with &if // A "has_*" member var for fields with &if
LetField* has_value_field_; LetField* has_value_field_;
// Attributes // Attributes
AttrList* attrs_; AttrList* attrs_;
Expr* attr_byteorder_expr_; Expr* attr_byteorder_expr_;
ExprList* attr_checks_; ExprList* attr_checks_;
ExprList* attr_enforces_; ExprList* attr_enforces_;
bool attr_chunked_; bool attr_chunked_;
bool attr_exportsourcedata_; bool attr_exportsourcedata_;
Expr* attr_if_expr_; Expr* attr_if_expr_;
Expr* attr_length_expr_; Expr* attr_length_expr_;
FieldList* attr_letfields_; FieldList* attr_letfields_;
Expr* attr_multiline_end_; Expr* attr_multiline_end_;
Expr* attr_linebreaker_; Expr* attr_linebreaker_;
bool attr_oneline_; bool attr_oneline_;
bool attr_refcount_; bool attr_refcount_;
ExprList* attr_requires_; ExprList* attr_requires_;
bool attr_restofdata_; bool attr_restofdata_;
bool attr_restofflow_; bool attr_restofflow_;
bool attr_transient_; bool attr_transient_;
public: public:
static void init(); static void init();
static bool CompatibleTypes(Type* type1, Type* type2); static bool CompatibleTypes(Type* type1, Type* type2);
static void AddPredefinedType(const string& type_name, Type* type); static void AddPredefinedType(const string& type_name, Type* type);
static Type* LookUpByID(ID* id); static Type* LookUpByID(ID* id);
protected: protected:
typedef map<string, Type*> type_map_t; typedef map<string, Type*> type_map_t;
static type_map_t type_map_; static type_map_t type_map_;
}; };
#endif // pac_type_h #endif // pac_type_h

View file

@ -16,315 +16,275 @@
#include "pac_type.h" #include "pac_type.h"
#include "pac_utils.h" #include "pac_utils.h"
TypeDecl::TypeDecl(ID* id, ParamList* params, Type* type) TypeDecl::TypeDecl(ID* id, ParamList* params, Type* type) : Decl(id, TYPE), params_(params), type_(type) {
: Decl(id, TYPE), params_(params), type_(type) env_ = nullptr;
{ type_->set_type_decl(this, true);
env_ = nullptr; }
type_->set_type_decl(this, true);
}
TypeDecl::~TypeDecl() TypeDecl::~TypeDecl() {
{ delete env_;
delete env_; delete type_;
delete type_;
delete_list(ParamList, params_); delete_list(ParamList, params_);
} }
void TypeDecl::ProcessAttr(Attr* a) void TypeDecl::ProcessAttr(Attr* a) { type_->ProcessAttr(a); }
{
type_->ProcessAttr(a);
}
void TypeDecl::AddParam(Param* param) void TypeDecl::AddParam(Param* param) {
{ // Cannot work after Prepare()
// Cannot work after Prepare() ASSERT(! env_);
ASSERT(! env_); params_->push_back(param);
params_->push_back(param); }
}
void TypeDecl::Prepare() void TypeDecl::Prepare() {
{ DEBUG_MSG("Preparing type %s\n", id()->Name());
DEBUG_MSG("Preparing type %s\n", id()->Name());
if ( type_->tot() != Type::EXTERN && type_->tot() != Type::DUMMY ) if ( type_->tot() != Type::EXTERN && type_->tot() != Type::DUMMY )
SetAnalyzerContext(); SetAnalyzerContext();
// As a type ID can be used in the same way function is, add the // As a type ID can be used in the same way function is, add the
// id as a FUNC_ID and set it as evaluated. // id as a FUNC_ID and set it as evaluated.
global_env()->AddID(id(), FUNC_ID, type_); global_env()->AddID(id(), FUNC_ID, type_);
global_env()->SetEvaluated(id()); global_env()->SetEvaluated(id());
env_ = new Env(global_env(), this); env_ = new Env(global_env(), this);
foreach (i, ParamList, params_) foreach (i, ParamList, params_) {
{ Param* p = *i;
Param* p = *i; // p->Prepare(env_);
// p->Prepare(env_); type_->AddField(p->param_field());
type_->AddField(p->param_field()); }
}
if ( type_->attr_byteorder_expr() ) if ( type_->attr_byteorder_expr() ) {
{ DEBUG_MSG("Adding byteorder field to %s\n", id()->Name());
DEBUG_MSG("Adding byteorder field to %s\n", id()->Name()); type_->AddField(new LetField(byteorder_id->clone(), extern_type_int, type_->attr_byteorder_expr()));
type_->AddField( }
new LetField(byteorder_id->clone(), extern_type_int, type_->attr_byteorder_expr()));
}
type_->Prepare(env_, Type::TO_BE_PARSED); type_->Prepare(env_, Type::TO_BE_PARSED);
} }
string TypeDecl::class_name() const string TypeDecl::class_name() const { return id_->Name(); }
{
return id_->Name();
}
void TypeDecl::GenForwardDeclaration(Output* out_h) void TypeDecl::GenForwardDeclaration(Output* out_h) {
{ // Do not generate declaration for external types
// Do not generate declaration for external types if ( type_->tot() == Type::EXTERN )
if ( type_->tot() == Type::EXTERN ) return;
return; out_h->println("class %s;", class_name().c_str());
out_h->println("class %s;", class_name().c_str()); }
}
void TypeDecl::GenCode(Output* out_h, Output* out_cc) void TypeDecl::GenCode(Output* out_h, Output* out_cc) {
{ // Do not generate code for external types
// Do not generate code for external types if ( type_->tot() == Type::EXTERN || type_->tot() == Type::STRING )
if ( type_->tot() == Type::EXTERN || type_->tot() == Type::STRING ) return;
return;
if ( !FLAGS_quiet ) if ( ! FLAGS_quiet )
fprintf(stderr, "Generating code for %s\n", class_name().c_str()); fprintf(stderr, "Generating code for %s\n", class_name().c_str());
if ( RequiresAnalyzerContext::compute(type_) ) if ( RequiresAnalyzerContext::compute(type_) ) {
{ DEBUG_MSG("%s requires analyzer context\n", id()->Name());
DEBUG_MSG("%s requires analyzer context\n", id()->Name()); Type* param_type = analyzer_context()->param_type();
Type* param_type = analyzer_context()->param_type(); env_->AddID(analyzer_context_id, TEMP_VAR, param_type);
env_->AddID(analyzer_context_id, TEMP_VAR, param_type); env_->SetEvaluated(analyzer_context_id);
env_->SetEvaluated(analyzer_context_id); env_->AddMacro(context_macro_id, new Expr(analyzer_context_id->clone()));
env_->AddMacro(context_macro_id, new Expr(analyzer_context_id->clone())); }
}
// Add parameter "byteorder" // Add parameter "byteorder"
if ( type_->RequiresByteOrder() && ! type_->attr_byteorder_expr() ) if ( type_->RequiresByteOrder() && ! type_->attr_byteorder_expr() ) {
{ env_->AddID(byteorder_id, TEMP_VAR, extern_type_int);
env_->AddID(byteorder_id, TEMP_VAR, extern_type_int); env_->SetEvaluated(byteorder_id);
env_->SetEvaluated(byteorder_id); }
}
vector<string> base_classes; vector<string> base_classes;
AddBaseClass(&base_classes); AddBaseClass(&base_classes);
if ( type_->attr_refcount() ) if ( type_->attr_refcount() )
base_classes.push_back(kRefCountClass); base_classes.push_back(kRefCountClass);
// The first line of class definition // The first line of class definition
out_h->println(""); out_h->println("");
out_h->print("class %s final", class_name().c_str()); out_h->print("class %s final", class_name().c_str());
bool first = true; bool first = true;
vector<string>::iterator i; vector<string>::iterator i;
for ( i = (&base_classes)->begin(); i != (&base_classes)->end(); ++i ) for ( i = base_classes.begin(); i != base_classes.end(); ++i ) {
{ if ( first ) {
if ( first ) out_h->print(" : public %s", i->c_str());
{ first = false;
out_h->print(" : public %s", i->c_str()); }
first = false; else
} out_h->print(", public %s", i->c_str());
else }
out_h->print(", public %s", i->c_str()); out_h->print("\n");
}
out_h->print("\n");
// Public members // Public members
out_h->println("{"); out_h->println("{");
out_h->println("public:"); out_h->println("public:");
out_h->inc_indent(); out_h->inc_indent();
GenConstructorFunc(out_h, out_cc); GenConstructorFunc(out_h, out_cc);
GenDestructorFunc(out_h, out_cc); GenDestructorFunc(out_h, out_cc);
if ( type_->attr_length_expr() ) if ( type_->attr_length_expr() )
GenInitialBufferLengthFunc(out_h, out_cc); GenInitialBufferLengthFunc(out_h, out_cc);
GenParseFunc(out_h, out_cc); GenParseFunc(out_h, out_cc);
out_h->println(""); out_h->println("");
out_h->println("// Member access functions"); out_h->println("// Member access functions");
type_->GenPubDecls(out_h, env_); type_->GenPubDecls(out_h, env_);
out_h->println(""); out_h->println("");
GenPubDecls(out_h, out_cc); GenPubDecls(out_h, out_cc);
out_h->dec_indent(); out_h->dec_indent();
out_h->println("protected:"); out_h->println("protected:");
out_h->inc_indent(); out_h->inc_indent();
GenPrivDecls(out_h, out_cc); GenPrivDecls(out_h, out_cc);
type_->GenPrivDecls(out_h, env_); type_->GenPrivDecls(out_h, env_);
out_h->dec_indent(); out_h->dec_indent();
out_h->println("};\n"); out_h->println("};\n");
} }
void TypeDecl::GenPubDecls(Output* out_h, Output* out_cc) void TypeDecl::GenPubDecls(Output* out_h, Output* out_cc) {
{ // GenParamPubDecls(params_, out_h, env_);
// GenParamPubDecls(params_, out_h, env_); }
}
void TypeDecl::GenPrivDecls(Output* out_h, Output* out_cc) void TypeDecl::GenPrivDecls(Output* out_h, Output* out_cc) {
{ // GenParamPrivDecls(params_, out_h, env_);
// GenParamPrivDecls(params_, out_h, env_); }
}
void TypeDecl::GenInitCode(Output* out_cc) { } void TypeDecl::GenInitCode(Output* out_cc) {}
void TypeDecl::GenCleanUpCode(Output* out_cc) { } void TypeDecl::GenCleanUpCode(Output* out_cc) {}
void TypeDecl::GenConstructorFunc(Output* out_h, Output* out_cc) void TypeDecl::GenConstructorFunc(Output* out_h, Output* out_cc) {
{ string params_str = ParamDecls(params_);
string params_str = ParamDecls(params_);
string proto = strfmt("%s(%s)", class_name().c_str(), params_str.c_str()); string proto = strfmt("%s(%s)", class_name().c_str(), params_str.c_str());
out_h->println("%s;", proto.c_str()); out_h->println("%s;", proto.c_str());
out_cc->println("%s::%s", class_name().c_str(), proto.c_str()); out_cc->println("%s::%s", class_name().c_str(), proto.c_str());
out_cc->inc_indent(); out_cc->inc_indent();
out_cc->println("{"); out_cc->println("{");
// GenParamAssignments(params_, out_cc, env_); // GenParamAssignments(params_, out_cc, env_);
type_->GenInitCode(out_cc, env_); type_->GenInitCode(out_cc, env_);
GenInitCode(out_cc); GenInitCode(out_cc);
out_cc->println("}\n"); out_cc->println("}\n");
out_cc->dec_indent(); out_cc->dec_indent();
} }
void TypeDecl::GenDestructorFunc(Output* out_h, Output* out_cc) void TypeDecl::GenDestructorFunc(Output* out_h, Output* out_cc) {
{ string proto = strfmt("~%s()", class_name().c_str());
string proto = strfmt("~%s()", class_name().c_str());
out_h->println("%s;", proto.c_str()); out_h->println("%s;", proto.c_str());
out_cc->println("%s::%s", class_name().c_str(), proto.c_str()); out_cc->println("%s::%s", class_name().c_str(), proto.c_str());
out_cc->inc_indent(); out_cc->inc_indent();
out_cc->println("{"); out_cc->println("{");
GenCleanUpCode(out_cc); GenCleanUpCode(out_cc);
type_->GenCleanUpCode(out_cc, env_); type_->GenCleanUpCode(out_cc, env_);
out_cc->println("}\n"); out_cc->println("}\n");
out_cc->dec_indent(); out_cc->dec_indent();
} }
string TypeDecl::ParseFuncPrototype(Env* env) string TypeDecl::ParseFuncPrototype(Env* env) {
{ const char* func_name = nullptr;
const char* func_name = nullptr; const char* return_type = nullptr;
const char* return_type = nullptr; string params;
string params;
if ( type_->incremental_input() ) if ( type_->incremental_input() ) {
{ func_name = kParseFuncWithBuffer;
func_name = kParseFuncWithBuffer; return_type = "bool";
return_type = "bool"; params = strfmt("flow_buffer_t %s", env->LValue(flow_buffer_id));
params = strfmt("flow_buffer_t %s", env->LValue(flow_buffer_id)); }
} else {
else func_name = kParseFuncWithoutBuffer;
{ return_type = "int";
func_name = kParseFuncWithoutBuffer; params = strfmt("const_byteptr const %s, const_byteptr const %s", env->LValue(begin_of_data),
return_type = "int"; env->LValue(end_of_data));
params = strfmt("const_byteptr const %s, const_byteptr const %s", }
env->LValue(begin_of_data), env->LValue(end_of_data));
}
if ( RequiresAnalyzerContext::compute(type_) ) if ( RequiresAnalyzerContext::compute(type_) ) {
{ Type* param_type = analyzer_context()->param_type();
Type* param_type = analyzer_context()->param_type(); params += strfmt(", %s %s", param_type->DataTypeConstRefStr().c_str(), env->LValue(analyzer_context_id));
params += strfmt(", %s %s", param_type->DataTypeConstRefStr().c_str(), }
env->LValue(analyzer_context_id));
}
// Add parameter "byteorder" // Add parameter "byteorder"
if ( type_->RequiresByteOrder() && ! type_->attr_byteorder_expr() ) if ( type_->RequiresByteOrder() && ! type_->attr_byteorder_expr() ) {
{ params += strfmt(", int %s", env->LValue(byteorder_id));
params += strfmt(", int %s", env->LValue(byteorder_id)); }
}
// Returns "<return type> %s<func name>(<params>)%s". // Returns "<return type> %s<func name>(<params>)%s".
return strfmt("%s %%s%s(%s)%%s", return_type, func_name, params.c_str()); return strfmt("%s %%s%s(%s)%%s", return_type, func_name, params.c_str());
} }
void TypeDecl::GenParsingEnd(Output* out_cc, Env* env, const DataPtr& data) void TypeDecl::GenParsingEnd(Output* out_cc, Env* env, const DataPtr& data) {
{ string ret_val_0, ret_val_1;
string ret_val_0, ret_val_1;
if ( type_->incremental_input() ) if ( type_->incremental_input() ) {
{ ret_val_0 = type_->parsing_complete(env).c_str();
ret_val_0 = type_->parsing_complete(env).c_str(); ret_val_1 = "false";
ret_val_1 = "false"; }
} else {
else ret_val_0 = type_->DataSize(nullptr, env, data).c_str();
{ ret_val_1 = "@@@";
ret_val_0 = type_->DataSize(nullptr, env, data).c_str();
ret_val_1 = "@@@";
out_cc->println("BINPAC_ASSERT(%s + (%s) <= %s);", env->RValue(begin_of_data), out_cc->println("BINPAC_ASSERT(%s + (%s) <= %s);", env->RValue(begin_of_data), ret_val_0.c_str(),
ret_val_0.c_str(), env->RValue(end_of_data)); env->RValue(end_of_data));
} }
if ( type_->incremental_parsing() && if ( type_->incremental_parsing() && (type_->tot() == Type::RECORD || type_->tot() == Type::ARRAY) ) {
(type_->tot() == Type::RECORD || type_->tot() == Type::ARRAY) ) // In which case parsing may jump to label
{ // "need_more_data" ...
// In which case parsing may jump to label out_cc->println("BINPAC_ASSERT(%s);", type_->parsing_complete(env).c_str());
// "need_more_data" ... out_cc->println("return %s;", ret_val_0.c_str());
out_cc->println("BINPAC_ASSERT(%s);", type_->parsing_complete(env).c_str());
out_cc->println("return %s;", ret_val_0.c_str());
out_cc->println(""); out_cc->println("");
out_cc->dec_indent(); out_cc->dec_indent();
out_cc->println("%s:", kNeedMoreData); out_cc->println("%s:", kNeedMoreData);
out_cc->inc_indent(); out_cc->inc_indent();
out_cc->println("BINPAC_ASSERT(!(%s));", type_->parsing_complete(env).c_str()); out_cc->println("BINPAC_ASSERT(!(%s));", type_->parsing_complete(env).c_str());
out_cc->println("return %s;", ret_val_1.c_str()); out_cc->println("return %s;", ret_val_1.c_str());
} }
else if ( type_->incremental_input() ) else if ( type_->incremental_input() ) {
{ out_cc->println("return %s;", ret_val_0.c_str());
out_cc->println("return %s;", ret_val_0.c_str()); }
} else {
else out_cc->println("return %s;", ret_val_0.c_str());
{ }
out_cc->println("return %s;", ret_val_0.c_str()); }
}
}
void TypeDecl::GenParseFunc(Output* out_h, Output* out_cc) void TypeDecl::GenParseFunc(Output* out_h, Output* out_cc) {
{ if ( type_->tot() == Type::DUMMY )
if ( type_->tot() == Type::DUMMY ) return;
return;
// Env within the parse function // Env within the parse function
Env p_func_env(env_, this); Env p_func_env(env_, this);
Env* env = &p_func_env; Env* env = &p_func_env;
if ( type_->incremental_input() ) if ( type_->incremental_input() ) {
{ env->AddID(flow_buffer_id, TEMP_VAR, extern_type_flowbuffer);
env->AddID(flow_buffer_id, TEMP_VAR, extern_type_flowbuffer); env->SetEvaluated(flow_buffer_id);
env->SetEvaluated(flow_buffer_id); }
} else {
else env->AddID(begin_of_data, TEMP_VAR, extern_type_const_byteptr);
{ env->AddID(end_of_data, TEMP_VAR, extern_type_const_byteptr);
env->AddID(begin_of_data, TEMP_VAR, extern_type_const_byteptr);
env->AddID(end_of_data, TEMP_VAR, extern_type_const_byteptr);
env->SetEvaluated(begin_of_data); env->SetEvaluated(begin_of_data);
env->SetEvaluated(end_of_data); env->SetEvaluated(end_of_data);
} }
string proto; string proto;
proto = ParseFuncPrototype(env); proto = ParseFuncPrototype(env);
#if 0 #if 0
if ( func_type == PARSE ) if ( func_type == PARSE )
@ -340,54 +300,48 @@ void TypeDecl::GenParseFunc(Output* out_h, Output* out_cc)
} }
#endif #endif
out_h->println(proto.c_str(), "", ";"); out_h->println(proto.c_str(), "", ";");
string tmp = strfmt("%s::", class_name().c_str()); string tmp = strfmt("%s::", class_name().c_str());
out_cc->println(proto.c_str(), tmp.c_str(), ""); out_cc->println(proto.c_str(), tmp.c_str(), "");
out_cc->inc_indent(); out_cc->inc_indent();
out_cc->println("{"); out_cc->println("{");
DataPtr data(env, nullptr, 0); DataPtr data(env, nullptr, 0);
if ( ! type_->incremental_input() ) if ( ! type_->incremental_input() )
data = DataPtr(env, begin_of_data, 0); data = DataPtr(env, begin_of_data, 0);
type_->GenParseCode(out_cc, env, data, 0); type_->GenParseCode(out_cc, env, data, 0);
GenParsingEnd(out_cc, env, data); GenParsingEnd(out_cc, env, data);
out_cc->println("}\n"); out_cc->println("}\n");
out_cc->dec_indent(); out_cc->dec_indent();
} }
void TypeDecl::GenInitialBufferLengthFunc(Output* out_h, Output* out_cc) void TypeDecl::GenInitialBufferLengthFunc(Output* out_h, Output* out_cc) {
{ string func(kInitialBufferLengthFunc);
string func(kInitialBufferLengthFunc);
int init_buffer_length = type_->InitialBufferLength(); int init_buffer_length = type_->InitialBufferLength();
if ( init_buffer_length < 0 ) // cannot be statically determined if ( init_buffer_length < 0 ) // cannot be statically determined
{ {
throw Exception(type()->attr_length_expr(), strfmt("cannot determine initial buffer length" throw Exception(type()->attr_length_expr(), strfmt("cannot determine initial buffer length"
" for type %s", " for type %s",
id_->Name())); id_->Name()));
} }
out_h->println("int %s() const { return %d; }", func.c_str(), init_buffer_length); out_h->println("int %s() const { return %d; }", func.c_str(), init_buffer_length);
} }
Type* TypeDecl::LookUpType(const ID* id) Type* TypeDecl::LookUpType(const ID* id) {
{ Decl* decl = LookUpDecl(id);
Decl* decl = LookUpDecl(id); if ( ! decl )
if ( ! decl ) return nullptr;
return nullptr; switch ( decl->decl_type() ) {
switch ( decl->decl_type() ) case TYPE:
{ case CONN:
case TYPE: case FLOW: return static_cast<TypeDecl*>(decl)->type();
case CONN: case ENUM: return static_cast<EnumDecl*>(decl)->DataType();
case FLOW: default: return nullptr;
return static_cast<TypeDecl*>(decl)->type(); }
case ENUM: }
return static_cast<EnumDecl*>(decl)->DataType();
default:
return nullptr;
}
}

View file

@ -3,45 +3,44 @@
#include "pac_decl.h" #include "pac_decl.h"
class TypeDecl : public Decl class TypeDecl : public Decl {
{
public: public:
TypeDecl(ID* arg_id, ParamList* arg_params, Type* arg_type); TypeDecl(ID* arg_id, ParamList* arg_params, Type* arg_type);
~TypeDecl() override; ~TypeDecl() override;
void Prepare() override; void Prepare() override;
void GenForwardDeclaration(Output* out_h) override; void GenForwardDeclaration(Output* out_h) override;
void GenCode(Output* out_h, Output* out_cc) override; void GenCode(Output* out_h, Output* out_cc) override;
Env* env() const override { return env_; } Env* env() const override { return env_; }
Type* type() const { return type_; } Type* type() const { return type_; }
string class_name() const; string class_name() const;
static Type* LookUpType(const ID* id); static Type* LookUpType(const ID* id);
protected: protected:
void AddParam(Param* param); void AddParam(Param* param);
virtual void AddBaseClass(vector<string>* base_classes) const { } virtual void AddBaseClass(vector<string>* base_classes) const {}
void ProcessAttr(Attr* a) override; void ProcessAttr(Attr* a) override;
virtual void GenPubDecls(Output* out_h, Output* out_cc); virtual void GenPubDecls(Output* out_h, Output* out_cc);
virtual void GenPrivDecls(Output* out_h, Output* out_cc); virtual void GenPrivDecls(Output* out_h, Output* out_cc);
virtual void GenInitCode(Output* out_cc); virtual void GenInitCode(Output* out_cc);
virtual void GenCleanUpCode(Output* out_cc); virtual void GenCleanUpCode(Output* out_cc);
void GenConstructorFunc(Output* out_h, Output* out_cc); void GenConstructorFunc(Output* out_h, Output* out_cc);
void GenDestructorFunc(Output* out_h, Output* out_cc); void GenDestructorFunc(Output* out_h, Output* out_cc);
string ParseFuncPrototype(Env* env); string ParseFuncPrototype(Env* env);
void GenParseFunc(Output* out_h, Output* out_cc); void GenParseFunc(Output* out_h, Output* out_cc);
void GenParsingEnd(Output* out_cc, Env* env, const DataPtr& data); void GenParsingEnd(Output* out_cc, Env* env, const DataPtr& data);
void GenInitialBufferLengthFunc(Output* out_h, Output* out_cc); void GenInitialBufferLengthFunc(Output* out_h, Output* out_cc);
protected: protected:
Env* env_; Env* env_;
ParamList* params_; ParamList* params_;
Type* type_; Type* type_;
}; };
#endif // pac_typedecl_h #endif // pac_typedecl_h

View file

@ -4,39 +4,34 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
char* copy_string(const char* s) char* copy_string(const char* s) {
{ char* c = new char[strlen(s) + 1];
char* c = new char[strlen(s) + 1]; strcpy(c, s);
strcpy(c, s); return c;
return c; }
}
namespace namespace {
{
const char* do_fmt(const char* format, va_list ap) const char* do_fmt(const char* format, va_list ap) {
{ static char buf[1024];
static char buf[1024]; vsnprintf(buf, sizeof(buf), format, ap);
vsnprintf(buf, sizeof(buf), format, ap); return buf;
return buf; }
}
} } // namespace
string strfmt(const char* format, ...) string strfmt(const char* format, ...) {
{ va_list ap;
va_list ap; va_start(ap, format);
va_start(ap, format); const char* r = do_fmt(format, ap);
const char* r = do_fmt(format, ap); va_end(ap);
va_end(ap); return string(r);
return string(r); }
}
char* nfmt(const char* format, ...) char* nfmt(const char* format, ...) {
{ va_list ap;
va_list ap; va_start(ap, format);
va_start(ap, format); const char* r = do_fmt(format, ap);
const char* r = do_fmt(format, ap); va_end(ap);
va_end(ap); return copy_string(r);
return copy_string(r); }
}

View file

@ -1,6 +1,3 @@
#include "pac_varfield.h" #include "pac_varfield.h"
void PrivVarField::Prepare(Env* env) void PrivVarField::Prepare(Env* env) { Field::Prepare(env); }
{
Field::Prepare(env);
}

View file

@ -4,54 +4,37 @@
#include "pac_field.h" #include "pac_field.h"
// A private variable evaluated with parsing // A private variable evaluated with parsing
class ParseVarField : public Field class ParseVarField : public Field {
{
public: public:
ParseVarField(int is_class_member, ID* id, Type* type) ParseVarField(int is_class_member, ID* id, Type* type)
: Field(PARSE_VAR_FIELD, TYPE_TO_BE_PARSED | is_class_member | NOT_PUBLIC_READABLE, id, : Field(PARSE_VAR_FIELD, TYPE_TO_BE_PARSED | is_class_member | NOT_PUBLIC_READABLE, id, type) {}
type) void GenPubDecls(Output* out, Env* env) override { /* do nothing */
{ }
} };
void GenPubDecls(Output* out, Env* env) override
{ /* do nothing */
}
};
// A public variable // A public variable
class PubVarField : public Field class PubVarField : public Field {
{
public: public:
PubVarField(ID* id, Type* type) PubVarField(ID* id, Type* type)
: Field(PUB_VAR_FIELD, TYPE_NOT_TO_BE_PARSED | CLASS_MEMBER | PUBLIC_READABLE, id, type) : Field(PUB_VAR_FIELD, TYPE_NOT_TO_BE_PARSED | CLASS_MEMBER | PUBLIC_READABLE, id, type) {}
{ ~PubVarField() override {}
} };
~PubVarField() override { }
};
// A private variable // A private variable
class PrivVarField : public Field class PrivVarField : public Field {
{
public: public:
PrivVarField(ID* id, Type* type) PrivVarField(ID* id, Type* type)
: Field(PRIV_VAR_FIELD, TYPE_NOT_TO_BE_PARSED | CLASS_MEMBER | NOT_PUBLIC_READABLE, id, : Field(PRIV_VAR_FIELD, TYPE_NOT_TO_BE_PARSED | CLASS_MEMBER | NOT_PUBLIC_READABLE, id, type) {}
type) ~PrivVarField() override {}
{
}
~PrivVarField() override { }
void GenPubDecls(Output* out, Env* env) override void GenPubDecls(Output* out, Env* env) override { /* do nothing */
{ /* do nothing */ }
} };
};
class TempVarField : public Field class TempVarField : public Field {
{
public: public:
TempVarField(ID* id, Type* type) TempVarField(ID* id, Type* type) : Field(TEMP_VAR_FIELD, TYPE_NOT_TO_BE_PARSED | NOT_CLASS_MEMBER, id, type) {}
: Field(TEMP_VAR_FIELD, TYPE_NOT_TO_BE_PARSED | NOT_CLASS_MEMBER, id, type) ~TempVarField() override {}
{ };
}
~TempVarField() override { }
};
#endif // pac_varfield_h #endif // pac_varfield_h

View file

@ -7,67 +7,54 @@
#include "pac_type.h" #include "pac_type.h"
WithInputField::WithInputField(ID* id, Type* type, InputBuffer* input) WithInputField::WithInputField(ID* id, Type* type, InputBuffer* input)
: Field(WITHINPUT_FIELD, TYPE_TO_BE_PARSED | CLASS_MEMBER | PUBLIC_READABLE, id, type), : Field(WITHINPUT_FIELD, TYPE_TO_BE_PARSED | CLASS_MEMBER | PUBLIC_READABLE, id, type), input_(input) {
input_(input) ASSERT(type_);
{ ASSERT(input_);
ASSERT(type_); }
ASSERT(input_);
}
WithInputField::~WithInputField() WithInputField::~WithInputField() { delete input_; }
{
delete input_;
}
bool WithInputField::DoTraverse(DataDepVisitor* visitor) bool WithInputField::DoTraverse(DataDepVisitor* visitor) {
{ return Field::DoTraverse(visitor) && input()->Traverse(visitor);
return Field::DoTraverse(visitor) && input()->Traverse(visitor); }
}
bool WithInputField::RequiresAnalyzerContext() const bool WithInputField::RequiresAnalyzerContext() const {
{ return Field::RequiresAnalyzerContext() || (input() && input()->RequiresAnalyzerContext());
return Field::RequiresAnalyzerContext() || (input() && input()->RequiresAnalyzerContext()); }
}
void WithInputField::Prepare(Env* env) void WithInputField::Prepare(Env* env) {
{ Field::Prepare(env);
Field::Prepare(env); env->SetEvalMethod(id_, this);
env->SetEvalMethod(id_, this); }
}
void WithInputField::GenEval(Output* out_cc, Env* env) void WithInputField::GenEval(Output* out_cc, Env* env) {
{ GenParseCode(out_cc, env);
GenParseCode(out_cc, env); if ( type_->attr_if_expr() ) {
if ( type_->attr_if_expr() ) out_cc->println("BINPAC_ASSERT(%s);", env->RValue(type_->has_value_var()));
{ }
out_cc->println("BINPAC_ASSERT(%s);", env->RValue(type_->has_value_var())); }
}
}
void WithInputField::GenParseCode(Output* out_cc, Env* env) void WithInputField::GenParseCode(Output* out_cc, Env* env) {
{ out_cc->println("// Parse \"%s\"", id_->Name());
out_cc->println("// Parse \"%s\"", id_->Name()); if ( type_->attr_if_expr() ) {
if ( type_->attr_if_expr() ) // A conditional field
{ env->Evaluate(out_cc, type_->has_value_var());
// A conditional field out_cc->println("if ( %s )", env->RValue(type_->has_value_var()));
env->Evaluate(out_cc, type_->has_value_var()); out_cc->inc_indent();
out_cc->println("if ( %s )", env->RValue(type_->has_value_var())); out_cc->println("{");
out_cc->inc_indent(); }
out_cc->println("{"); else
} out_cc->println("{");
else
out_cc->println("{");
Env field_env(env, this); Env field_env(env, this);
ASSERT(! type_->incremental_input()); ASSERT(! type_->incremental_input());
type_->GenPreParsing(out_cc, &field_env); type_->GenPreParsing(out_cc, &field_env);
type_->GenParseCode(out_cc, &field_env, input()->GenDataBeginEnd(out_cc, &field_env), 0); type_->GenParseCode(out_cc, &field_env, input()->GenDataBeginEnd(out_cc, &field_env), 0);
if ( type_->attr_if_expr() ) if ( type_->attr_if_expr() ) {
{ out_cc->println("}");
out_cc->println("}"); out_cc->dec_indent();
out_cc->dec_indent(); }
} else
else out_cc->println("}");
out_cc->println("}"); }
}

View file

@ -5,34 +5,33 @@
#include "pac_decl.h" #include "pac_decl.h"
#include "pac_field.h" #include "pac_field.h"
class WithInputField : public Field, public Evaluatable class WithInputField : public Field, public Evaluatable {
{
public: public:
WithInputField(ID* id, Type* type, InputBuffer* input); WithInputField(ID* id, Type* type, InputBuffer* input);
~WithInputField() override; ~WithInputField() override;
InputBuffer* input() const { return input_; } InputBuffer* input() const { return input_; }
void Prepare(Env* env) override; void Prepare(Env* env) override;
// void GenPubDecls(Output* out, Env* env); // void GenPubDecls(Output* out, Env* env);
// void GenPrivDecls(Output* out, Env* env); // void GenPrivDecls(Output* out, Env* env);
// void GenInitCode(Output* out, Env* env); // void GenInitCode(Output* out, Env* env);
// void GenCleanUpCode(Output* out, Env* env); // void GenCleanUpCode(Output* out, Env* env);
void GenParseCode(Output* out, Env* env); void GenParseCode(Output* out, Env* env);
// Instantiate the Evaluatable interface // Instantiate the Evaluatable interface
void GenEval(Output* out, Env* env) override; void GenEval(Output* out, Env* env) override;
bool RequiresAnalyzerContext() const override; bool RequiresAnalyzerContext() const override;
protected: protected:
bool DoTraverse(DataDepVisitor* visitor) override; bool DoTraverse(DataDepVisitor* visitor) override;
protected: protected:
InputBuffer* input_; InputBuffer* input_;
}; };
#endif // pac_withinput_h #endif // pac_withinput_h