charliee1151 wrote:
...
Here is my command line, using the "l" (labels) command:
disasm6 code7.nes -lcode7.lbl -c -r
Here is my one-line custom label file, made with Notepad:
VBlank = $c014
Yet, the asm output is still:
__c014: lda PPUSTATUS ; $c014: ad 02 20
What do I need to do to get the label to work?
The source code to disasm6 is provided (it's in PHP). So let's look at it, shall we? Sadly this source code is not on GitHub or anywhere I can find other than nesdev, so I have to copy-paste it here directly. First, we find that the usage syntax is:
Code:
echo <<<ENDOFSTRING
Usage:
disasm6 <file> [-t <file>] [-o #] [-l <file>] [-cdl <file>] [-cdlo #] [-d] [-i]
[-h] [-c] [-p #] [-r] [-lc] [-uc] [-fs #] [-cs #] [-fe #] [-ce <#>]
[-len #] [-iw] [-m2]
That means
disasm6 -l filename not
disasm6 -lfilename. You choosing to exclude the space is a bad habit. Not all argv parsers are going to be able to handle that properly; maybe you wanted
-l -f -i shorthand as
-lfi for example. See my point? So going forward, comply with the usage syntax. This may or may not be your problem; let's assume it isn't and continue on.
Code:
$labelFile = false;
...
// check command line params
for ($i = 2; $i < $argc; $i++)
{
$nextParam = false;
if (isset($argv[$i + 1]) && substr($argv[$i + 1],0,1) != '-')
{ $nextParam = $argv[$i + 1];
}
switch (strtolower($argv[$i]))
{
...
case '-l':
case '-labels':
if (!$nextParam || !file_exists($nextParam))
{ outputHelp("You must specify a valid file");
}
$labelFile = $argv[++$i];
break;
Okay, so we can see here that $labelFile is probably getting set to the filename passed as an argument. So what uses this variable?
Code:
$labelLen = 0;
if ($labelFile !== false)
{
$fileLabels = readLabels($labelFile);
//$mapperArr = $fileLabels['mapperArr'];
//unset($fileLabels['mapperArr']);
$labelLen = $fileLabels['maxLength'] - 10;
$labelLen = $labelLen < 0 ? 0: $labelLen;
unset ($fileLabels['maxLength']);
$initLabels += $fileLabels;
}
Okay, so from this we can see that
readLabels() is what ideally does the parsing of the file. Let's look at that.
Code:
function readLabels($filename)
{
$arr = readLabelText(file_get_contents($filename));
return $arr;
}
Deeper into the rabbit hole we go, and more abstraction for no justified reason, hooray! The only thing that uses
readLabelText() is
readLabels(). It's also fantastically super awesomely amazing that the way this works is by passing the
ENTIRE FILE CONTENTS as an argument, rather than just handing it a file handle or reference! *cough* So, let's look at that function...
Code:
function readLabelText($str)
{
$arr = array();
$len = 0;
$str = preg_replace('%;.*$%m', '', $str);
if (preg_match_all('%^\s*([a-zA-Z0-9_\-\+\@]*)\s*\=\s*([\$\%]*)([a-fA-F0-9]*)%m', $str, $matches))
{
foreach($matches[0] as $n => $v)
{ $matches[1][$n] = trim($matches[1][$n]);
$thislen = strlen($matches[1][$n]);
if ($thislen > $len)
{
$len = $thislen;
}
if (strlen($matches[1][$n]) > 0)
{
if ($matches[2][$n] == '')
{ $matches[3][$n] = dechex_pad($matches[3][$n]);
}
if ($matches[2][$n] == '%')
{
$matches[3][$n] = dechex_pad(bindec($matches[3][$n]));
}
$arr[strtolower($matches[3][$n])] = $matches[1][$n];
}
}
}
$arr['maxLength'] = $len;
return $arr;
}
Now we're into it. The first thing you can see is how there's absolutely no error checking or emission of errors -- if your label file doesn't match the
preg_match_all(), then it silently says nothing. Very user-friendly!
The
$str = preg_replace('%;.*$%m', '', $str); essentially deletes/ignore any lines that start with
; (i.e. comments). The author chose to use
% as the delimiter instead of
/.
The
if (preg_match_all('%^\s*([a-zA-Z0-9_\-\+\@]*)\s*\=\s*([\$\%]*)([a-fA-F0-9]*)%m', $str, $matches)) is what does the "line matching". It's a very long regex, so let's try to turn it into an English sentence:
*
^ -- anchor at beginning of the line
*
\s* -- zero or more spaces
*
([a-zA-Z0-9_\-\+\@]*) -- zero or more characters in the ranges a-z, A-Z, 0-9, underscore, hyphen, plus, or at-symbol -- and if matched, save the contents into array (not string!)
$matches[0]*
\s* -- zero or more spaces
*
= -- an equals sign
*
\s* -- zero or more spaces
*
([\$\%]*) -- zero or more characters of dollar-sign or percentage -- and if matched, save the contents into array
$matches[1]*
([a-fA-F0-9]*) -- zero or more characters in the ranges a-f, A-F, or 0-9 (i.e. valid hexadecimal values in upper or lowercase) -- and if matched, save the contents into array
$matches[2]So based on this, the following label assignments should be 100% valid:
Code:
mylabel = $abc0
otherlabel = 12345
In this case,
$matches[0][0] would contain
mylabel,
$matches[1][0] would contain
$ (address base designation, hex in this case), and
$matches[2][0] would contain
abc0.
I have no idea why there's a special case for
% (percentange) as a unit. Maybe binary? I don't know as of right now.
The code then iterates over all the entries in
$matches[0], assigning the key to
$n and the value to
$v.
It then issues
trim() on each correlating entry in
$matches[1][$n] (trims off newlines, carriage returns, and spaces from start and end of the address base designation) and stores it back into
$matches[1][$n]It then checks the length of the string of
$matches[1][$n] and if it's greater than
$len (which starts at 0), then it assigns $len to the length of the string. I guess this is some kind of "max string length" test scenario, though I'm not sure why (it looks like it all gets used later on in some magic key called maxLength in the
$arr array. Anyway...)
It then explicitly checks for the length of the string
$matches[1][$n] to be greater than 0 (probably as a safety net due to crappy parsing ;-) ). If true:
It then compares
$matches[2][$n] to
'' (an empty string). If it's true, it uses
dechex_pad() to turn -- I'm guessing here -- a decimal value in
$matches[3][$n] into something. I haven't looked at
dechex_pad() yet. It stores the result back in
$matches[3][$n]. This is a new key/array entry in $matches.
It then compares
$matches[2][$n] to
'$' (dollar sign). If it's true, it uses
dechex_pad(bindec()) to turn -- again, guessing -- a hexadecimal value in
$matches[3][$n] into something. It stores the result back in
$matches[3][$n]. This is a new key/array entry in $matches.
Finally, it populates the array
$arr, using a key of the lowercased string version of
$matches[3][$n], with a value of
$matches[1][$n].
It then, before returning the array itself, populates
$arr['maxLength'] with
$len from earlier.
How all this works past this point is beyond me -- it would require a lot more RE'ing than I'm willing to put in. It looks like this tool can also **generate** label files, and the syntax it uses it kind of obvious:
Code:
function outputLabels($arr, $text)
{
global $origin;
$ret = commentHeader($text);
foreach ($arr as $n => $v)
{
if ($n == 'maxLength')
{
continue;
}
if (hexdec($n) < $origin)
{
$ret .= str_pad($v , 20) . ' = $' . $n . "\n";
}
}
return $ret;
}
Looks to me like
label = $address.
I hope this helps. But odds are if you want to troubleshoot/debug this yourself, you're going to need a full PHP install on the system and start running the .php script directly through the interpreter (i.e. not using disasm6.exe) and add some debugging echo/print statements, etc...