mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 10:12:06 +00:00
Implement ? suffix to "quiet" a context and exclude it from backtraces (#1800)
This commit is contained in:
@@ -42,7 +42,7 @@ local args=(
|
||||
'(-v --verbose)'{-v,--verbose}'[Enable verbose output]'
|
||||
-w'[Disable all warnings]'
|
||||
|
||||
'(-B --backtrace)'{-B,--backtrace}'+[Set backtrace depth or style]:depth:'
|
||||
'(-B --backtrace)'{-B,--backtrace}'+[Set backtrace depth or style]:param:'
|
||||
'(-b --binary-digits)'{-b,--binary-digits}'+[Change chars for binary constants]:digit spec:'
|
||||
--color'[Whether to use color in output]:color:(auto always never)'
|
||||
'*'{-D,--define}'+[Define a string symbol]:name + value (default 1):'
|
||||
|
||||
@@ -28,7 +28,7 @@ local args=(
|
||||
'(-w --wramx)'{-w,--wramx}'[Disable WRAM banking]'
|
||||
'(-x --nopad)'{-x,--nopad}'[Disable padding the end of the final file]'
|
||||
|
||||
'(-B --backtrace)'{-B,--backtrace}'+[Set backtrace depth or style]:depth:'
|
||||
'(-B --backtrace)'{-B,--backtrace}'+[Set backtrace depth or style]:param:'
|
||||
--color'[Whether to use color in output]:color:(auto always never)'
|
||||
'(-l --linkerscript)'{-l,--linkerscript}"+[Use a linker script]:linker script:_files -g '*.link'"
|
||||
'(-M --no-sym-in-map)'{-M,--no-sym-in-map}'[Do not output symbol names in map file]'
|
||||
|
||||
@@ -24,6 +24,7 @@ struct FileStackNode {
|
||||
std::string // NODE_FILE, NODE_MACRO
|
||||
>
|
||||
data;
|
||||
bool isQuiet; // Whether to omit this node from error reporting
|
||||
|
||||
std::shared_ptr<FileStackNode> parent; // Pointer to parent node, for error reporting
|
||||
// Line at which the parent context was exited
|
||||
@@ -40,8 +41,12 @@ struct FileStackNode {
|
||||
std::string &name() { return std::get<std::string>(data); }
|
||||
std::string const &name() const { return std::get<std::string>(data); }
|
||||
|
||||
FileStackNode(FileStackNodeType type_, std::variant<std::vector<uint32_t>, std::string> data_)
|
||||
: type(type_), data(data_) {}
|
||||
FileStackNode(
|
||||
FileStackNodeType type_,
|
||||
std::variant<std::vector<uint32_t>, std::string> data_,
|
||||
bool isQuiet_
|
||||
)
|
||||
: type(type_), data(data_), isQuiet(isQuiet_) {}
|
||||
|
||||
void printBacktrace(uint32_t curLineNo) const;
|
||||
};
|
||||
@@ -62,16 +67,19 @@ bool fstk_FileError(std::string const &path, char const *functionName);
|
||||
bool fstk_FailedOnMissingInclude();
|
||||
|
||||
bool yywrap();
|
||||
bool fstk_RunInclude(std::string const &path);
|
||||
void fstk_RunMacro(std::string const ¯oName, std::shared_ptr<MacroArgs> macroArgs);
|
||||
void fstk_RunRept(uint32_t count, int32_t reptLineNo, ContentSpan const &span);
|
||||
bool fstk_RunInclude(std::string const &path, bool isQuiet);
|
||||
void fstk_RunMacro(
|
||||
std::string const ¯oName, std::shared_ptr<MacroArgs> macroArgs, bool isQuiet
|
||||
);
|
||||
void fstk_RunRept(uint32_t count, int32_t reptLineNo, ContentSpan const &span, bool isQuiet);
|
||||
void fstk_RunFor(
|
||||
std::string const &symName,
|
||||
int32_t start,
|
||||
int32_t stop,
|
||||
int32_t step,
|
||||
int32_t reptLineNo,
|
||||
ContentSpan const &span
|
||||
ContentSpan const &span,
|
||||
bool isQuiet
|
||||
);
|
||||
bool fstk_Break();
|
||||
|
||||
|
||||
@@ -30,8 +30,9 @@ bool sym_IsPC(Symbol const *sym); // Forward declaration for `getSection`
|
||||
struct Symbol {
|
||||
std::string name;
|
||||
SymbolType type;
|
||||
bool isExported; // Whether the symbol is to be exported
|
||||
bool isBuiltin; // Whether the symbol is a built-in
|
||||
bool isBuiltin;
|
||||
bool isExported; // Not relevant for SYM_MACRO or SYM_EQUS
|
||||
bool isQuiet; // Only relevant for SYM_MACRO
|
||||
Section *section;
|
||||
std::shared_ptr<FileStackNode> src; // Where the symbol was defined
|
||||
uint32_t fileLine; // Line where the symbol was defined
|
||||
@@ -88,7 +89,9 @@ Symbol *sym_FindScopedSymbol(std::string const &symName);
|
||||
// Find a scoped symbol by name; do not return `@` or `_NARG` when they have no value
|
||||
Symbol *sym_FindScopedValidSymbol(std::string const &symName);
|
||||
Symbol const *sym_GetPC();
|
||||
Symbol *sym_AddMacro(std::string const &symName, int32_t defLineNo, ContentSpan const &span);
|
||||
Symbol *sym_AddMacro(
|
||||
std::string const &symName, int32_t defLineNo, ContentSpan const &span, bool isQuiet
|
||||
);
|
||||
Symbol *sym_Ref(std::string const &symName);
|
||||
Symbol *sym_AddString(std::string const &symName, std::shared_ptr<std::string> value);
|
||||
Symbol *sym_RedefString(std::string const &symName, std::shared_ptr<std::string> value);
|
||||
|
||||
@@ -11,58 +11,74 @@
|
||||
|
||||
#include "style.hpp"
|
||||
|
||||
static constexpr uint64_t TRACE_COLLAPSE = UINT64_MAX;
|
||||
struct Tracing {
|
||||
uint64_t depth = 0;
|
||||
bool collapse = false;
|
||||
bool loud = false;
|
||||
};
|
||||
|
||||
extern uint64_t traceDepth;
|
||||
extern Tracing tracing;
|
||||
|
||||
bool trace_ParseTraceDepth(char const *arg);
|
||||
|
||||
template<typename T, typename M, typename N>
|
||||
void trace_PrintBacktrace(std::vector<T> const &stack, M getName, N getLineNo) {
|
||||
auto printLocation = [&](T const &item) {
|
||||
size_t n = stack.size();
|
||||
if (n == 0) {
|
||||
return; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
auto printLocation = [&](size_t i) {
|
||||
T const &item = stack[n - i - 1];
|
||||
style_Reset(stderr);
|
||||
if (!tracing.collapse) {
|
||||
fputs(" ", stderr); // Just three spaces; the fourth will be printed next
|
||||
}
|
||||
fprintf(stderr, " %s ", i == 0 ? "at" : "<-");
|
||||
style_Set(stderr, STYLE_CYAN, true);
|
||||
fputs(getName(item), stderr);
|
||||
style_Set(stderr, STYLE_CYAN, false);
|
||||
fprintf(stderr, "(%" PRIu32 ")", getLineNo(item));
|
||||
if (!tracing.collapse) {
|
||||
putc('\n', stderr);
|
||||
}
|
||||
};
|
||||
|
||||
size_t n = stack.size();
|
||||
|
||||
if (traceDepth == TRACE_COLLAPSE) {
|
||||
if (tracing.collapse) {
|
||||
fputs(" ", stderr); // Just three spaces; the fourth will be handled by the loop
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
style_Reset(stderr);
|
||||
fprintf(stderr, " %s ", i == 0 ? "at" : "<-");
|
||||
printLocation(stack[n - i - 1]);
|
||||
}
|
||||
putc('\n', stderr);
|
||||
} else if (traceDepth == 0 || static_cast<size_t>(traceDepth) >= n) {
|
||||
|
||||
if (tracing.depth == 0 || static_cast<size_t>(tracing.depth) >= n) {
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
style_Reset(stderr);
|
||||
fprintf(stderr, " %s ", i == 0 ? "at" : "<-");
|
||||
printLocation(stack[n - i - 1]);
|
||||
putc('\n', stderr);
|
||||
printLocation(i);
|
||||
}
|
||||
} else {
|
||||
size_t last = traceDepth / 2;
|
||||
size_t first = traceDepth - last;
|
||||
size_t skipped = n - traceDepth;
|
||||
size_t last = tracing.depth / 2;
|
||||
size_t first = tracing.depth - last;
|
||||
size_t skipped = n - tracing.depth;
|
||||
for (size_t i = 0; i < first; ++i) {
|
||||
style_Reset(stderr);
|
||||
fprintf(stderr, " %s ", i == 0 ? "at" : "<-");
|
||||
printLocation(stack[n - i - 1]);
|
||||
putc('\n', stderr);
|
||||
printLocation(i);
|
||||
}
|
||||
style_Reset(stderr);
|
||||
fprintf(stderr, " ...%zu more%s\n", skipped, last ? "..." : "");
|
||||
for (size_t i = n - last; i < n; ++i) {
|
||||
style_Reset(stderr);
|
||||
fputs(" <- ", stderr);
|
||||
printLocation(stack[n - i - 1]);
|
||||
|
||||
if (tracing.collapse) {
|
||||
fputs(" <-", stderr);
|
||||
} else {
|
||||
fputs(" ", stderr); // Just three spaces; the fourth will be printed next
|
||||
}
|
||||
fprintf(stderr, " ...%zu more%s", skipped, last ? "..." : "");
|
||||
if (!tracing.collapse) {
|
||||
putc('\n', stderr);
|
||||
}
|
||||
|
||||
for (size_t i = n - last; i < n; ++i) {
|
||||
printLocation(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (tracing.collapse) {
|
||||
putc('\n', stderr);
|
||||
}
|
||||
style_Reset(stderr);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ struct FileStackNode {
|
||||
std::string // NODE_FILE, NODE_MACRO
|
||||
>
|
||||
data;
|
||||
bool isQuiet; // Whether to omit this node from error reporting
|
||||
|
||||
FileStackNode *parent;
|
||||
// Line at which the parent context was exited; meaningless for the root level
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include "helpers.hpp" // assume
|
||||
|
||||
#define RGBDS_OBJECT_VERSION_STRING "RGB9"
|
||||
#define RGBDS_OBJECT_REV 12U
|
||||
#define RGBDS_OBJECT_REV 13U
|
||||
|
||||
enum AssertionType { ASSERT_WARN, ASSERT_ERROR, ASSERT_FATAL };
|
||||
|
||||
@@ -78,12 +78,18 @@ enum SectionType {
|
||||
SECTTYPE_INVALID
|
||||
};
|
||||
|
||||
static constexpr uint8_t SECTTYPE_TYPE_MASK = 0b111;
|
||||
static constexpr uint8_t SECTTYPE_UNION_BIT = 7;
|
||||
static constexpr uint8_t SECTTYPE_FRAGMENT_BIT = 6;
|
||||
|
||||
enum FileStackNodeType {
|
||||
NODE_REPT,
|
||||
NODE_FILE,
|
||||
NODE_MACRO,
|
||||
};
|
||||
|
||||
static constexpr uint8_t FSTACKNODE_QUIET_BIT = 7;
|
||||
|
||||
// Nont-`const` members may be patched in RGBLINK depending on CLI flags
|
||||
extern struct SectionTypeInfo {
|
||||
std::string const name;
|
||||
|
||||
34
man/rgbasm.1
34
man/rgbasm.1
@@ -9,7 +9,7 @@
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl EhVvw
|
||||
.Op Fl B Ar depth
|
||||
.Op Fl B Ar param
|
||||
.Op Fl b Ar chars
|
||||
.Op Fl \-color Ar when
|
||||
.Op Fl D Ar name Ns Op = Ns Ar value
|
||||
@@ -53,15 +53,29 @@ is invalid because it could also be
|
||||
.Fl \-version .
|
||||
The arguments are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl B Ar depth , Fl \-backtrace Ar depth
|
||||
Specifies the maximum depth for which
|
||||
.Nm
|
||||
will print location backtraces for warnings or errors.
|
||||
Deeper backtraces than that will be abbreviated.
|
||||
.Fl B Ar 0
|
||||
allows unlimited-depth backtraces.
|
||||
.Fl B Ar collapse
|
||||
will print the entire location trace on one line.
|
||||
.It Fl B Ar param , Fl \-backtrace Ar param
|
||||
Configures how location backtraces are printed if warnings or errors occur.
|
||||
This flag may be specified multiple times with different parameters that combine meaningfully.
|
||||
If
|
||||
.Ar param
|
||||
is a positive number, it specifies the maximum backtrace depth, abbreviating deeper ones.
|
||||
Other valid parameter values are the following:
|
||||
.Bl -tag -width Ds
|
||||
.It Cm 0
|
||||
Do not limit the maximum backtrace depth; this is the default.
|
||||
.It Cm all
|
||||
Force all locations to be printed, even "quiet" ones (see
|
||||
.Dq Excluding locations from backtraces
|
||||
in
|
||||
.Xr rgbasm 5
|
||||
for details).
|
||||
.It Cm no-all
|
||||
Do not print "quieted" locations in backtraces; this is the default.
|
||||
.It Cm collapse
|
||||
Print all locations on one line.
|
||||
.It Cm no-collapse
|
||||
Print one location per line; this is the default.
|
||||
.El
|
||||
.It Fl b Ar chars , Fl \-binary-digits Ar chars
|
||||
Allow two characters to be used for binary constants in addition to the default
|
||||
.Sq 0
|
||||
|
||||
65
man/rgbasm.5
65
man/rgbasm.5
@@ -1681,7 +1681,8 @@ $ rgbasm -o a.o a.asm
|
||||
$ rgbasm -o b.o b.asm
|
||||
$ rgbasm -o c.o c.asm
|
||||
$ rgblink a.o b.o c.o
|
||||
error: c.asm(2): Unknown symbol "LabelA"
|
||||
error: Undefined symbol "LabelA"
|
||||
at c.asm(2)
|
||||
Linking failed with 1 error
|
||||
.Ed
|
||||
.Pp
|
||||
@@ -2516,6 +2517,68 @@ PUSHO b.X, g.oOX
|
||||
DW `..ooOOXX
|
||||
POPO
|
||||
.Ed
|
||||
.Ss Excluding locations from backtraces
|
||||
Errors and warnings print
|
||||
.Em backtraces
|
||||
showing the location in the source file where the problem occurred, tracing the origin of the problem even through a chain of
|
||||
.Ic REPT ,
|
||||
.Ic FOR ,
|
||||
.Ic MACRO ,
|
||||
and
|
||||
.Ic INCLUDE
|
||||
locations.
|
||||
Sometimes there are locations you would like to ignore; for example, a common utility macro when you only care about the line where the macro is used, or an
|
||||
.Ic INCLUDE
|
||||
file that only serves to include other files and is just filler in the backtrace.
|
||||
.Pp
|
||||
In those cases, you can
|
||||
.Em silence
|
||||
a location with a question mark
|
||||
.Sq \&?
|
||||
after the token: all of the locations created by a
|
||||
.Sq REPT? ,
|
||||
.Sq FOR? ,
|
||||
or
|
||||
.Sq MACRO?
|
||||
will not be printed, and any location created by a
|
||||
.Sq INCLUDE? ,
|
||||
or a macro invocation whose name is immediately followed by a
|
||||
.Sq \&? ,
|
||||
will not be printed.
|
||||
For example, if this were assembled as
|
||||
.Ql example.asm :
|
||||
.Bd -literal -offset indent
|
||||
MACRO lb
|
||||
assert -128 <= (\e2) && (\e2) < 256, "\e2 is not a byte"
|
||||
assert -128 <= (\e3) && (\e3) < 256, "\e3 is not a byte"
|
||||
ld \e1, (LOW(\e2) << 8) | LOW(\e3)
|
||||
ENDM
|
||||
SECTION "Code", ROM0
|
||||
lb hl, $123, $45
|
||||
.Ed
|
||||
.Pp
|
||||
This would print an error backtrace:
|
||||
.Bd -literal -offset indent
|
||||
error: Assertion failed: $123 is not a byte
|
||||
at example.asm::lb(2)
|
||||
<- example.asm(7)
|
||||
.Ed
|
||||
.Pp
|
||||
But if
|
||||
.Ql MACRO
|
||||
were changed to
|
||||
.Ql MACRO? ,
|
||||
or
|
||||
.Ql lb hl
|
||||
were changed to
|
||||
.Ql lb? hl ,
|
||||
then the error backtrace would not mention the location within the
|
||||
.Ql lb
|
||||
macro:
|
||||
.Bd -literal -offset indent
|
||||
error: Assertion failed: $123 is not a byte
|
||||
at example.asm(7)
|
||||
.Ed
|
||||
.Sh SEE ALSO
|
||||
.Xr rgbasm 1 ,
|
||||
.Xr rgblink 1 ,
|
||||
|
||||
@@ -79,12 +79,16 @@ order, meaning the node with ID 0 is the last one in the list!
|
||||
.It Cm LONG Ar ParentLineNo
|
||||
Line at which the parent node's context was exited; meaningless for the root node.
|
||||
.It Cm BYTE Ar Type
|
||||
Bits 0\(en6 indicate the node's type:
|
||||
.Bl -column "Value" -compact
|
||||
.It Sy Value Ta Sy Meaning
|
||||
.It 0 Ta REPT node
|
||||
.It 1 Ta File node
|
||||
.It 2 Ta Macro node
|
||||
.El
|
||||
.Pp
|
||||
Bit\ 7 being set means that the node is "quieted"
|
||||
.Pq see Do Excluding locations from backtraces Dc in Xr rgbasm 5 .
|
||||
.It Cm IF Ar Type No \(!= 0
|
||||
If the node is not a REPT node...
|
||||
.Pp
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
.Sh SYNOPSIS
|
||||
.Nm
|
||||
.Op Fl dhMtVvwx
|
||||
.Op Fl B Ar depth
|
||||
.Op Fl B Ar param
|
||||
.Op Fl \-color Ar when
|
||||
.Op Fl l Ar linker_script
|
||||
.Op Fl m Ar map_file
|
||||
@@ -65,15 +65,29 @@ is invalid because it could also be
|
||||
.Fl \-version .
|
||||
The arguments are as follows:
|
||||
.Bl -tag -width Ds
|
||||
.It Fl B Ar depth , Fl \-backtrace Ar depth
|
||||
Specifies the maximum depth for which
|
||||
.Nm
|
||||
will print location backtraces for warnings or errors.
|
||||
Deeper backtraces than that will be abbreviated.
|
||||
.Fl B Ar 0
|
||||
allows unlimited-depth backtraces.
|
||||
.Fl B Ar collapse
|
||||
will print the entire location trace on one line.
|
||||
.It Fl B Ar param , Fl \-backtrace Ar param
|
||||
Configures how location backtraces are printed if warnings or errors occur.
|
||||
This flag may be specified multiple times with different parameters that combine meaningfully.
|
||||
If
|
||||
.Ar param
|
||||
is a positive number, it specifies the maximum backtrace depth, abbreviating deeper ones.
|
||||
Other valid parameter values are the following:
|
||||
.Bl -tag -width Ds
|
||||
.It Cm 0
|
||||
Do not limit the maximum backtrace depth; this is the default.
|
||||
.It Cm all
|
||||
Force all locations to be printed, even "quiet" ones (see
|
||||
.Dq Excluding locations from backtraces
|
||||
in
|
||||
.Xr rgbasm 5
|
||||
for details).
|
||||
.It Cm no-all
|
||||
Do not print "quieted" locations in backtraces; this is the default.
|
||||
.It Cm collapse
|
||||
Print all locations on one line.
|
||||
.It Cm no-collapse
|
||||
Print one location per line; this is the default.
|
||||
.El
|
||||
.It Fl \-color Ar when
|
||||
Specify when to highlight warning and error messages with color:
|
||||
.Ql always ,
|
||||
|
||||
@@ -63,6 +63,16 @@ static std::string reptChain(FileStackNode const &node) {
|
||||
using TraceNode = std::pair<std::string, uint32_t>;
|
||||
|
||||
static std::vector<TraceNode> backtrace(FileStackNode const &node, uint32_t curLineNo) {
|
||||
if (node.isQuiet && !tracing.loud) {
|
||||
if (node.parent) {
|
||||
// Quiet REPT nodes will pass their interior line number up to their parent,
|
||||
// which is more precise than the parent's own line number (since that will be
|
||||
// the line number of the "REPT?" or "FOR?" itself).
|
||||
return backtrace(*node.parent, node.type == NODE_REPT ? curLineNo : node.lineNo);
|
||||
}
|
||||
return {}; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
if (!node.parent) {
|
||||
assume(node.type != NODE_REPT && std::holds_alternative<std::string>(node.data));
|
||||
return {
|
||||
@@ -244,14 +254,14 @@ static void checkRecursionDepth() {
|
||||
}
|
||||
}
|
||||
|
||||
static void newFileContext(std::string const &filePath, bool updateStateNow) {
|
||||
static void newFileContext(std::string const &filePath, bool isQuiet, bool updateStateNow) {
|
||||
checkRecursionDepth();
|
||||
|
||||
std::shared_ptr<std::string> uniqueIDStr = nullptr;
|
||||
std::shared_ptr<MacroArgs> macroArgs = nullptr;
|
||||
|
||||
auto fileInfo =
|
||||
std::make_shared<FileStackNode>(NODE_FILE, filePath == "-" ? "<stdin>" : filePath);
|
||||
std::make_shared<FileStackNode>(NODE_FILE, filePath == "-" ? "<stdin>" : filePath, isQuiet);
|
||||
if (!contextStack.empty()) {
|
||||
Context &oldContext = contextStack.top();
|
||||
fileInfo->parent = oldContext.fileInfo;
|
||||
@@ -269,7 +279,8 @@ static void newFileContext(std::string const &filePath, bool updateStateNow) {
|
||||
context.lexerState.setFileAsNextState(filePath, updateStateNow);
|
||||
}
|
||||
|
||||
static void newMacroContext(Symbol const ¯o, std::shared_ptr<MacroArgs> macroArgs) {
|
||||
static void
|
||||
newMacroContext(Symbol const ¯o, std::shared_ptr<MacroArgs> macroArgs, bool isQuiet) {
|
||||
checkRecursionDepth();
|
||||
|
||||
Context &oldContext = contextStack.top();
|
||||
@@ -287,7 +298,7 @@ static void newMacroContext(Symbol const ¯o, std::shared_ptr<MacroArgs> macr
|
||||
fileInfoName.append("::");
|
||||
fileInfoName.append(macro.name);
|
||||
|
||||
auto fileInfo = std::make_shared<FileStackNode>(NODE_MACRO, fileInfoName);
|
||||
auto fileInfo = std::make_shared<FileStackNode>(NODE_MACRO, fileInfoName, isQuiet);
|
||||
assume(!contextStack.empty()); // The top level context cannot be a MACRO
|
||||
fileInfo->parent = oldContext.fileInfo;
|
||||
fileInfo->lineNo = lexer_GetLineNo();
|
||||
@@ -301,7 +312,8 @@ static void newMacroContext(Symbol const ¯o, std::shared_ptr<MacroArgs> macr
|
||||
context.lexerState.setViewAsNextState("MACRO", macro.getMacro(), macro.fileLine);
|
||||
}
|
||||
|
||||
static Context &newReptContext(int32_t reptLineNo, ContentSpan const &span, uint32_t count) {
|
||||
static Context &
|
||||
newReptContext(int32_t reptLineNo, ContentSpan const &span, uint32_t count, bool isQuiet) {
|
||||
checkRecursionDepth();
|
||||
|
||||
Context &oldContext = contextStack.top();
|
||||
@@ -312,7 +324,7 @@ static Context &newReptContext(int32_t reptLineNo, ContentSpan const &span, uint
|
||||
fileInfoIters.insert(fileInfoIters.end(), RANGE(oldContext.fileInfo->iters()));
|
||||
}
|
||||
|
||||
auto fileInfo = std::make_shared<FileStackNode>(NODE_REPT, fileInfoIters);
|
||||
auto fileInfo = std::make_shared<FileStackNode>(NODE_REPT, fileInfoIters, isQuiet);
|
||||
assume(!contextStack.empty()); // The top level context cannot be a REPT
|
||||
fileInfo->parent = oldContext.fileInfo;
|
||||
fileInfo->lineNo = reptLineNo;
|
||||
@@ -356,15 +368,17 @@ bool fstk_FailedOnMissingInclude() {
|
||||
return failedOnMissingInclude;
|
||||
}
|
||||
|
||||
bool fstk_RunInclude(std::string const &path) {
|
||||
bool fstk_RunInclude(std::string const &path, bool isQuiet) {
|
||||
if (std::optional<std::string> fullPath = fstk_FindFile(path); fullPath) {
|
||||
newFileContext(*fullPath, false);
|
||||
newFileContext(*fullPath, isQuiet, false);
|
||||
return false;
|
||||
}
|
||||
return fstk_FileError(path, "INCLUDE");
|
||||
}
|
||||
|
||||
void fstk_RunMacro(std::string const ¯oName, std::shared_ptr<MacroArgs> macroArgs) {
|
||||
void fstk_RunMacro(
|
||||
std::string const ¯oName, std::shared_ptr<MacroArgs> macroArgs, bool isQuiet
|
||||
) {
|
||||
Symbol *macro = sym_FindExactSymbol(macroName);
|
||||
|
||||
if (!macro) {
|
||||
@@ -380,15 +394,15 @@ void fstk_RunMacro(std::string const ¯oName, std::shared_ptr<MacroArgs> macr
|
||||
return;
|
||||
}
|
||||
|
||||
newMacroContext(*macro, macroArgs);
|
||||
newMacroContext(*macro, macroArgs, isQuiet || macro->isQuiet);
|
||||
}
|
||||
|
||||
void fstk_RunRept(uint32_t count, int32_t reptLineNo, ContentSpan const &span) {
|
||||
void fstk_RunRept(uint32_t count, int32_t reptLineNo, ContentSpan const &span, bool isQuiet) {
|
||||
if (count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
newReptContext(reptLineNo, span, count);
|
||||
newReptContext(reptLineNo, span, count, isQuiet);
|
||||
}
|
||||
|
||||
void fstk_RunFor(
|
||||
@@ -397,7 +411,8 @@ void fstk_RunFor(
|
||||
int32_t stop,
|
||||
int32_t step,
|
||||
int32_t reptLineNo,
|
||||
ContentSpan const &span
|
||||
ContentSpan const &span,
|
||||
bool isQuiet
|
||||
) {
|
||||
if (Symbol *sym = sym_AddVar(symName, start); sym->type != SYM_VAR) {
|
||||
return;
|
||||
@@ -422,7 +437,7 @@ void fstk_RunFor(
|
||||
return;
|
||||
}
|
||||
|
||||
Context &context = newReptContext(reptLineNo, span, count);
|
||||
Context &context = newReptContext(reptLineNo, span, count, isQuiet);
|
||||
context.isForLoop = true;
|
||||
context.forValue = start;
|
||||
context.forStep = step;
|
||||
@@ -447,11 +462,11 @@ void fstk_NewRecursionDepth(size_t newDepth) {
|
||||
}
|
||||
|
||||
void fstk_Init(std::string const &mainPath) {
|
||||
newFileContext(mainPath, true);
|
||||
newFileContext(mainPath, false, true);
|
||||
|
||||
for (std::string const &name : preIncludeNames) {
|
||||
if (std::optional<std::string> fullPath = fstk_FindFile(name); fullPath) {
|
||||
newFileContext(*fullPath, false);
|
||||
newFileContext(*fullPath, false, false);
|
||||
} else {
|
||||
error("Error reading pre-included file \"%s\": %s", name.c_str(), strerror(errno));
|
||||
}
|
||||
|
||||
@@ -1561,9 +1561,8 @@ static bool isGarbageCharacter(int c) {
|
||||
if (isWhitespace(c)) {
|
||||
return false;
|
||||
}
|
||||
// Printable characters which are nevertheless garbage: braces should have been interpolated,
|
||||
// and question mark is unused
|
||||
if (c == '{' || c == '}' || c == '?') {
|
||||
// Printable characters which are nevertheless garbage: braces should have been interpolated
|
||||
if (c == '{' || c == '}') {
|
||||
return true;
|
||||
}
|
||||
// All other printable characters are not garbage (i.e. `yylex_NORMAL` handles them), and
|
||||
@@ -1614,6 +1613,9 @@ static Token yylex_NORMAL() {
|
||||
case '~':
|
||||
return Token(T_(OP_NOT));
|
||||
|
||||
case '?':
|
||||
return Token(T_(QUESTIONMARK));
|
||||
|
||||
case '@': {
|
||||
std::string symName("@");
|
||||
return Token(T_(SYMBOL), symName);
|
||||
@@ -1926,22 +1928,23 @@ static Token yylex_NORMAL() {
|
||||
}
|
||||
}
|
||||
|
||||
// We need to distinguish between label definitions (which start with `LABEL`) and
|
||||
// macro invocations (which start with `SYMBOL`).
|
||||
// We need to distinguish between:
|
||||
// - label definitions (which are followed by a ':' and use the token `LABEL`)
|
||||
// - quiet macro invocations (which are followed by a '?' and use the token `QMACRO`)
|
||||
// - regular macro invocations (which use the token `SYMBOL`)
|
||||
//
|
||||
// If we had one `IDENTIFIER` token, the parser would need to perform "lookahead" to
|
||||
// determine which rule applies. But since macros need to enter "raw" mode to parse
|
||||
// their arguments, which may not even be valid tokens in "normal" mode, we cannot use
|
||||
// lookahead to check for the presence of a `COLON`.
|
||||
// lookahead to check for the presence of a `COLON` or `QUESTIONMARK`.
|
||||
//
|
||||
// Instead, we have separate `SYMBOL` and `LABEL` tokens, lexing as a `LABEL` if a ':'
|
||||
// character *immediately* follows the identifier. Thus, "Label:" and "mac:" are treated
|
||||
// as label definitions, but "Label :" and "mac :" are treated as macro invocations.
|
||||
//
|
||||
// The alternative would be a "lexer hack" like C, where identifiers would lex as a
|
||||
// `SYMBOL` if they are already defined, otherwise as a `LABEL`.
|
||||
if (token.type == T_(SYMBOL) && peek() == ':') {
|
||||
token.type = T_(LABEL);
|
||||
// Instead, we have separate `SYMBOL`, `LABEL`, and `QMACRO` tokens, and decide which
|
||||
// one to lex depending on the character *immediately* following the identifier.
|
||||
// Thus "name:" is a label definition, and "name?" is a quiet macro invocation, but
|
||||
// "name :" and "name ?" and just "name" are all regular macro invocations.
|
||||
if (token.type == T_(SYMBOL)) {
|
||||
c = peek();
|
||||
token.type = c == ':' ? T_(LABEL) : c == '?' ? T_(QMACRO) : T_(SYMBOL);
|
||||
}
|
||||
|
||||
return token;
|
||||
|
||||
@@ -83,10 +83,10 @@ static void writeSection(Section const §, FILE *file) {
|
||||
|
||||
putLong(sect.size, file);
|
||||
|
||||
assume((sect.type & SECTTYPE_TYPE_MASK) == sect.type);
|
||||
bool isUnion = sect.modifier == SECTION_UNION;
|
||||
bool isFragment = sect.modifier == SECTION_FRAGMENT;
|
||||
|
||||
putc(sect.type | isUnion << 7 | isFragment << 6, file);
|
||||
putc(sect.type | isUnion << SECTTYPE_UNION_BIT | isFragment << SECTTYPE_FRAGMENT_BIT, file);
|
||||
|
||||
putLong(sect.org, file);
|
||||
putLong(sect.bank, file);
|
||||
@@ -268,7 +268,9 @@ static void writeAssert(Assertion const &assert, FILE *file) {
|
||||
static void writeFileStackNode(FileStackNode const &node, FILE *file) {
|
||||
putLong(node.parent ? node.parent->ID : UINT32_MAX, file);
|
||||
putLong(node.lineNo, file);
|
||||
putc(node.type, file);
|
||||
|
||||
putc(node.type | node.isQuiet << FSTACKNODE_QUIET_BIT, file);
|
||||
|
||||
if (node.type != NODE_REPT) {
|
||||
putString(node.name(), file);
|
||||
} else {
|
||||
|
||||
@@ -98,6 +98,7 @@
|
||||
%token LBRACK "[" RBRACK "]"
|
||||
%token LBRACKS "[[" RBRACKS "]]"
|
||||
%token LPAREN "(" RPAREN ")"
|
||||
%token QUESTIONMARK "?"
|
||||
|
||||
// Arithmetic operators
|
||||
%token OP_ADD "+" OP_SUB "-"
|
||||
@@ -322,6 +323,7 @@
|
||||
%token <std::string> LABEL "label"
|
||||
%token <std::string> LOCAL "local label"
|
||||
%token <std::string> ANON "anonymous label"
|
||||
%token <std::string> QMACRO "quiet macro"
|
||||
|
||||
/******************** Data types ********************/
|
||||
|
||||
@@ -398,6 +400,7 @@
|
||||
%type <SectionType> sect_type
|
||||
%type <StrFmtArgList> strfmt_args
|
||||
%type <StrFmtArgList> strfmt_va_args
|
||||
%type <bool> maybe_quiet
|
||||
|
||||
%%
|
||||
|
||||
@@ -544,7 +547,13 @@ macro:
|
||||
// Parsing 'macro_args' will restore the lexer's normal mode
|
||||
lexer_SetMode(LEXER_RAW);
|
||||
} macro_args {
|
||||
fstk_RunMacro($1, $3);
|
||||
fstk_RunMacro($1, $3, false);
|
||||
}
|
||||
| QMACRO {
|
||||
// Parsing 'macro_args' will restore the lexer's normal mode
|
||||
lexer_SetMode(LEXER_RAW);
|
||||
} macro_args {
|
||||
fstk_RunMacro($1, $3, true);
|
||||
}
|
||||
;
|
||||
|
||||
@@ -780,10 +789,19 @@ load:
|
||||
}
|
||||
;
|
||||
|
||||
maybe_quiet:
|
||||
%empty {
|
||||
$$ = false;
|
||||
}
|
||||
| QUESTIONMARK {
|
||||
$$ = true;
|
||||
}
|
||||
;
|
||||
|
||||
rept:
|
||||
POP_REPT uconst NEWLINE capture_rept endofline {
|
||||
if ($4.span.ptr) {
|
||||
fstk_RunRept($2, $4.lineNo, $4.span);
|
||||
POP_REPT maybe_quiet uconst NEWLINE capture_rept endofline {
|
||||
if ($5.span.ptr) {
|
||||
fstk_RunRept($3, $5.lineNo, $5.span, $2);
|
||||
}
|
||||
}
|
||||
;
|
||||
@@ -791,11 +809,11 @@ rept:
|
||||
for:
|
||||
POP_FOR {
|
||||
lexer_ToggleStringExpansion(false);
|
||||
} SYMBOL {
|
||||
} maybe_quiet SYMBOL {
|
||||
lexer_ToggleStringExpansion(true);
|
||||
} COMMA for_args NEWLINE capture_rept endofline {
|
||||
if ($8.span.ptr) {
|
||||
fstk_RunFor($3, $6.start, $6.stop, $6.step, $8.lineNo, $8.span);
|
||||
if ($9.span.ptr) {
|
||||
fstk_RunFor($4, $7.start, $7.stop, $7.step, $9.lineNo, $9.span, $3);
|
||||
}
|
||||
}
|
||||
;
|
||||
@@ -835,11 +853,11 @@ break:
|
||||
def_macro:
|
||||
POP_MACRO {
|
||||
lexer_ToggleStringExpansion(false);
|
||||
} SYMBOL {
|
||||
} maybe_quiet SYMBOL {
|
||||
lexer_ToggleStringExpansion(true);
|
||||
} NEWLINE capture_macro endofline {
|
||||
if ($6.span.ptr) {
|
||||
sym_AddMacro($3, $6.lineNo, $6.span);
|
||||
if ($7.span.ptr) {
|
||||
sym_AddMacro($4, $7.lineNo, $7.span, $3);
|
||||
}
|
||||
}
|
||||
;
|
||||
@@ -1002,8 +1020,8 @@ export_def:
|
||||
;
|
||||
|
||||
include:
|
||||
label POP_INCLUDE string endofline {
|
||||
if (fstk_RunInclude($3)) {
|
||||
label POP_INCLUDE maybe_quiet string endofline {
|
||||
if (fstk_RunInclude($4, $3)) {
|
||||
YYACCEPT;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,8 +205,9 @@ static Symbol &createSymbol(std::string const &symName) {
|
||||
Symbol &sym = symbols[symName];
|
||||
|
||||
sym.name = symName;
|
||||
sym.isExported = false;
|
||||
sym.isBuiltin = false;
|
||||
sym.isExported = false;
|
||||
sym.isQuiet = false;
|
||||
sym.section = nullptr;
|
||||
sym.src = fstk_GetFileStack();
|
||||
sym.fileLine = sym.src ? lexer_GetLineNo() : 0;
|
||||
@@ -616,7 +617,9 @@ void sym_Export(std::string const &symName) {
|
||||
sym->isExported = true;
|
||||
}
|
||||
|
||||
Symbol *sym_AddMacro(std::string const &symName, int32_t defLineNo, ContentSpan const &span) {
|
||||
Symbol *sym_AddMacro(
|
||||
std::string const &symName, int32_t defLineNo, ContentSpan const &span, bool isQuiet
|
||||
) {
|
||||
Symbol *sym = createNonrelocSymbol(symName, false);
|
||||
|
||||
if (!sym) {
|
||||
@@ -625,6 +628,7 @@ Symbol *sym_AddMacro(std::string const &symName, int32_t defLineNo, ContentSpan
|
||||
|
||||
sym->type = SYM_MACRO;
|
||||
sym->data = span;
|
||||
sym->isQuiet = isQuiet;
|
||||
|
||||
sym->src = fstk_GetFileStack();
|
||||
// The symbol is created at the line after the `ENDM`,
|
||||
|
||||
@@ -6,16 +6,24 @@
|
||||
|
||||
#include "platform.hpp" // strcasecmp
|
||||
|
||||
uint64_t traceDepth = 0;
|
||||
Tracing tracing;
|
||||
|
||||
bool trace_ParseTraceDepth(char const *arg) {
|
||||
if (!strcasecmp(arg, "collapse")) {
|
||||
traceDepth = TRACE_COLLAPSE;
|
||||
tracing.collapse = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
} else if (!strcasecmp(arg, "no-collapse")) {
|
||||
tracing.collapse = false;
|
||||
return true;
|
||||
} else if (!strcasecmp(arg, "all")) {
|
||||
tracing.loud = true;
|
||||
return true;
|
||||
} else if (!strcasecmp(arg, "no-all")) {
|
||||
tracing.loud = false;
|
||||
return true;
|
||||
} else {
|
||||
char *endptr;
|
||||
traceDepth = strtoul(arg, &endptr, 0);
|
||||
|
||||
return arg[0] != '\0' && *endptr == '\0' && traceDepth != TRACE_COLLAPSE;
|
||||
tracing.depth = strtoul(arg, &endptr, 0);
|
||||
return arg[0] != '\0' && *endptr == '\0';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,16 @@
|
||||
using TraceNode = std::pair<std::string, uint32_t>;
|
||||
|
||||
static std::vector<TraceNode> backtrace(FileStackNode const &node, uint32_t curLineNo) {
|
||||
if (node.isQuiet && !tracing.loud) {
|
||||
if (node.parent) {
|
||||
// Quiet REPT nodes will pass their interior line number up to their parent,
|
||||
// which is more precise than the parent's own line number (since that will be
|
||||
// the line number of the "REPT?" or "FOR?" itself).
|
||||
return backtrace(*node.parent, node.type == NODE_REPT ? curLineNo : node.lineNo);
|
||||
}
|
||||
return {}; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
if (!node.parent) {
|
||||
assume(node.type != NODE_REPT && std::holds_alternative<std::string>(node.data));
|
||||
return {
|
||||
|
||||
@@ -105,14 +105,12 @@ static void readFileStackNode(
|
||||
tryReadLong(
|
||||
node.lineNo, file, "%s: Cannot read node #%" PRIu32 "'s line number: %s", fileName, nodeID
|
||||
);
|
||||
tryGetc(
|
||||
FileStackNodeType,
|
||||
node.type,
|
||||
file,
|
||||
"%s: Cannot read node #%" PRIu32 "'s type: %s",
|
||||
fileName,
|
||||
nodeID
|
||||
);
|
||||
|
||||
uint8_t type;
|
||||
tryGetc(uint8_t, type, file, "%s: Cannot read node #%" PRIu32 "'s type: %s", fileName, nodeID);
|
||||
node.type = static_cast<FileStackNodeType>(type & ~(1 << FSTACKNODE_QUIET_BIT));
|
||||
node.isQuiet = (type & (1 << FSTACKNODE_QUIET_BIT)) != 0;
|
||||
|
||||
switch (node.type) {
|
||||
case NODE_FILE:
|
||||
case NODE_MACRO:
|
||||
@@ -318,14 +316,14 @@ static void readSection(
|
||||
tryGetc(
|
||||
uint8_t, byte, file, "%s: Cannot read \"%s\"'s type: %s", fileName, section.name.c_str()
|
||||
);
|
||||
if (uint8_t type = byte & 0x3F; type >= SECTTYPE_INVALID) {
|
||||
if (uint8_t type = byte & SECTTYPE_TYPE_MASK; type >= SECTTYPE_INVALID) {
|
||||
fatal("\"%s\" has unknown section type 0x%02x", section.name.c_str(), type);
|
||||
} else {
|
||||
section.type = SectionType(type);
|
||||
}
|
||||
if (byte >> 7) {
|
||||
if (byte & (1 << SECTTYPE_UNION_BIT)) {
|
||||
section.modifier = SECTION_UNION;
|
||||
} else if (byte >> 6) {
|
||||
} else if (byte & (1 << SECTTYPE_FRAGMENT_BIT)) {
|
||||
section.modifier = SECTION_FRAGMENT;
|
||||
} else {
|
||||
section.modifier = SECTION_NORMAL;
|
||||
@@ -458,6 +456,7 @@ void obj_ReadFile(char const *fileName, unsigned int fileID) {
|
||||
nodes[fileID].push_back({
|
||||
.type = NODE_FILE,
|
||||
.data = std::variant<std::monostate, std::vector<uint32_t>, std::string>(fileName),
|
||||
.isQuiet = false,
|
||||
.parent = nullptr,
|
||||
.lineNo = 0,
|
||||
});
|
||||
|
||||
@@ -1 +1 @@
|
||||
-B 5
|
||||
-B 5 -B no-collapse
|
||||
|
||||
@@ -1 +1 @@
|
||||
-B 0
|
||||
-B no-collapse
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
assert 1 +# 1 == 2
|
||||
assert 2 ?<EFBFBD>* 2 == 4
|
||||
assert 3 **?<EFBFBD>?##?? 3 == 27
|
||||
assert 2 #<EFBFBD>* 2 == 4
|
||||
assert 3 **#<EFBFBD>}<EFBFBD># 3 == 27
|
||||
charmap "x", 4
|
||||
assert 4 <<#<EFBFBD>'x' == 64
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
error: Invalid character '#'
|
||||
at garbage_sequence.asm(1)
|
||||
error: Invalid characters '?', 0xFF (is the file UTF-8?)
|
||||
error: Invalid characters '#', 0xFF (is the file UTF-8?)
|
||||
at garbage_sequence.asm(2)
|
||||
error: Invalid characters '?', 0xFF, '?' (is the file UTF-8?)
|
||||
error: Invalid characters '#', 0xFF, '}', 0xFF (is the file UTF-8?)
|
||||
at garbage_sequence.asm(3)
|
||||
error: Invalid character '#'
|
||||
at garbage_sequence.asm(3)
|
||||
error: Invalid characters '#', '?', '?'
|
||||
at garbage_sequence.asm(3)
|
||||
error: Invalid characters '#', 0xFF (is the file UTF-8?)
|
||||
at garbage_sequence.asm(5)
|
||||
Assembly aborted with 6 errors!
|
||||
Assembly aborted with 5 errors!
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
error: syntax error, unexpected label, expecting symbol
|
||||
at lex-label.asm(1)
|
||||
error: syntax error, unexpected label, expecting symbol
|
||||
error: syntax error, unexpected label, expecting ? or symbol
|
||||
at lex-label.asm(3)
|
||||
error: syntax error, unexpected ENDM
|
||||
at lex-label.asm(4)
|
||||
error: syntax error, unexpected label, expecting symbol
|
||||
error: syntax error, unexpected label, expecting ? or symbol
|
||||
at lex-label.asm(6)
|
||||
error: syntax error, unexpected ENDR
|
||||
at lex-label.asm(7)
|
||||
|
||||
20
test/asm/loud-backtrace.asm
Normal file
20
test/asm/loud-backtrace.asm
Normal file
@@ -0,0 +1,20 @@
|
||||
macro mac
|
||||
warn "from macro"
|
||||
endm
|
||||
mac ; normal
|
||||
|
||||
macro? quiet
|
||||
warn "from quiet macro"
|
||||
endm
|
||||
quiet
|
||||
rept? 1
|
||||
warn "from quiet rept"
|
||||
endr
|
||||
for? x, 1
|
||||
warn "from quiet for (x={d:x})"
|
||||
endr
|
||||
include? "loud-backtrace.inc"
|
||||
macro loud
|
||||
warn "from loud macro"
|
||||
endm
|
||||
mac?
|
||||
12
test/asm/loud-backtrace.err
Normal file
12
test/asm/loud-backtrace.err
Normal file
@@ -0,0 +1,12 @@
|
||||
warning: from macro [-Wuser]
|
||||
at loud-backtrace.asm::mac(2) <- loud-backtrace.asm(4)
|
||||
warning: from quiet macro [-Wuser]
|
||||
at loud-backtrace.asm::quiet(7) <- loud-backtrace.asm(9)
|
||||
warning: from quiet rept [-Wuser]
|
||||
at loud-backtrace.asm::REPT~1(11) <- loud-backtrace.asm(10)
|
||||
warning: from quiet for (x=0) [-Wuser]
|
||||
at loud-backtrace.asm::REPT~1(14) <- loud-backtrace.asm(13)
|
||||
warning: from quiet include [-Wuser]
|
||||
at loud-backtrace.inc(1) <- loud-backtrace.asm(16)
|
||||
warning: from macro [-Wuser]
|
||||
at loud-backtrace.asm::mac(2) <- loud-backtrace.asm(20)
|
||||
1
test/asm/loud-backtrace.flags
Normal file
1
test/asm/loud-backtrace.flags
Normal file
@@ -0,0 +1 @@
|
||||
-B all
|
||||
1
test/asm/loud-backtrace.inc
Normal file
1
test/asm/loud-backtrace.inc
Normal file
@@ -0,0 +1 @@
|
||||
warn "from quiet include"
|
||||
20
test/asm/quiet-backtrace.asm
Normal file
20
test/asm/quiet-backtrace.asm
Normal file
@@ -0,0 +1,20 @@
|
||||
macro mac
|
||||
warn "from macro"
|
||||
endm
|
||||
mac ; normal
|
||||
|
||||
macro? quiet
|
||||
warn "from quiet macro"
|
||||
endm
|
||||
quiet
|
||||
rept? 1
|
||||
warn "from quiet rept"
|
||||
endr
|
||||
for? x, 1
|
||||
warn "from quiet for (x={d:x})"
|
||||
endr
|
||||
include? "quiet-backtrace.inc"
|
||||
macro loud
|
||||
warn "from loud macro"
|
||||
endm
|
||||
mac?
|
||||
12
test/asm/quiet-backtrace.err
Normal file
12
test/asm/quiet-backtrace.err
Normal file
@@ -0,0 +1,12 @@
|
||||
warning: from macro [-Wuser]
|
||||
at quiet-backtrace.asm::mac(2) <- quiet-backtrace.asm(4)
|
||||
warning: from quiet macro [-Wuser]
|
||||
at quiet-backtrace.asm(9)
|
||||
warning: from quiet rept [-Wuser]
|
||||
at quiet-backtrace.asm(11)
|
||||
warning: from quiet for (x=0) [-Wuser]
|
||||
at quiet-backtrace.asm(14)
|
||||
warning: from quiet include [-Wuser]
|
||||
at quiet-backtrace.asm(16)
|
||||
warning: from macro [-Wuser]
|
||||
at quiet-backtrace.asm(20)
|
||||
1
test/asm/quiet-backtrace.inc
Normal file
1
test/asm/quiet-backtrace.inc
Normal file
@@ -0,0 +1 @@
|
||||
warn "from quiet include"
|
||||
@@ -1 +1 @@
|
||||
-B 0
|
||||
-B no-collapse
|
||||
|
||||
Reference in New Issue
Block a user