diff --git a/spicy/toolchain/include/compiler/detail/codegen/parser-builder.h b/spicy/toolchain/include/compiler/detail/codegen/parser-builder.h index ed2fe89221..d951427779 100644 --- a/spicy/toolchain/include/compiler/detail/codegen/parser-builder.h +++ b/spicy/toolchain/include/compiler/detail/codegen/parser-builder.h @@ -355,6 +355,15 @@ class ParserBuilder { */ void waitForEod(); + /* + * Generates code which waits for given input length to be available to + * immediately consume and trim it. + * + * @param size an unsigned integer specifying the length of the input to skip + * @param location location associated with the operation + */ + void skip(const Expression& size, const Meta& location = {}); + /** Returns a boolean expression that's true if EOD has been reached. */ Expression atEod(); diff --git a/spicy/toolchain/src/compiler/codegen/parser-builder.cc b/spicy/toolchain/src/compiler/codegen/parser-builder.cc index b895c9495e..0b93434d77 100644 --- a/spicy/toolchain/src/compiler/codegen/parser-builder.cc +++ b/spicy/toolchain/src/compiler/codegen/parser-builder.cc @@ -1,5 +1,7 @@ // Copyright (c) 2020-2023 by the Zeek Project. See LICENSE for details. +#include "compiler/detail/codegen/parser-builder.h" + #include #include #include @@ -30,7 +32,6 @@ #include #include #include -#include #include #include @@ -1699,20 +1700,6 @@ struct ProductionVisitor } void operator()(const production::Skip& p) { - auto consumeFixedSize = [&](const Expression& size) { - assert(size.type().template isA()); - - auto n = builder()->addTmp("skip", size); - auto loop = builder()->addWhile(builder::greater(n, builder::integer(0U))); - pushBuilder(loop, [&]() { - pb->waitForInput(builder::integer(1U), "not enough bytes for skipping", p.location()); - auto consume = builder()->addTmp("consume", builder::min(builder::size(state().cur), size)); - pb->advanceInput(consume); - builder()->addAssign(n, builder::difference(n, consume)); - builder()->addDebugMsg("spicy-verbose", "- skipped %u bytes (%u left to skip)", {consume, n}); - }); - }; - if ( auto c = p.field().condition() ) pushBuilder(builder()->addIf(*c)); @@ -1721,7 +1708,7 @@ struct ProductionVisitor } else if ( const auto& size = p.field().size() ) - consumeFixedSize(*size); + pb->skip(*size, p.location()); else if ( p.field().parseType().isA() ) { // Bytes with fixed size already handled above. @@ -2403,6 +2390,20 @@ void ParserBuilder::waitForEod() { builder()->addCall("spicy_rt::waitForEod", {state().data, state().cur, _filters(state())}); } +void ParserBuilder::skip(const Expression& size, const Meta& location) { + assert(size.type().template isA()); + + auto n = builder()->addTmp("skip", size); + auto loop = builder()->addWhile(builder::greater(n, builder::integer(0U))); + pushBuilder(loop, [&]() { + waitForInput(builder::integer(1U), "not enough bytes for skipping", location); + auto consume = builder()->addTmp("consume", builder::min(builder::size(state().cur), size)); + advanceInput(consume); + builder()->addAssign(n, builder::difference(n, consume)); + builder()->addDebugMsg("spicy-verbose", "- skipped %u bytes (%u left to skip)", {consume, n}); + }); +} + void ParserBuilder::parseError(const Expression& error_msg, const Meta& location) { builder()->addThrow(builder::exception(builder::typeByID("spicy_rt::ParseError"), error_msg, location), location); }