#!/usr/bin/perl ############################################################################### # # # main.c # # # # Convert a ca65 source into HTML # # # # # # # # (C) 2000 Ullrich von Bassewitz # # Wacholderweg 14 # # D-70597 Stuttgart # # EMail: uz@musoftware.de # # # # # # This software is provided 'as-is', without any expressed or implied # # warranty. In no event will the authors be held liable for any damages # # arising from the use of this software. # # # # Permission is granted to anyone to use this software for any purpose, # # including commercial applications, and to alter it and redistribute it # # freely, subject to the following restrictions: # # # # 1. The origin of this software must not be misrepresented; you must not # # claim that you wrote the original software. If you use this software # # in a product, an acknowledgment in the product documentation would be # # appreciated but is not required. # # 2. Altered source versions must be plainly marked as such, and must not # # be misrepresented as being the original software. # # 3. This notice may not be removed or altered from any source # # distribution. # # # ############################################################################### #-----------------------------------------------------------------------------# # Variables # # ----------------------------------------------------------------------------# %Files = (); # List of all files. %Exports = (); # List of exported symbol. Value is html tag. %Labels = (); # List of all labels $LabelNum = 0; # Counter to generate unique labels #-----------------------------------------------------------------------------# # Helper functions # # ----------------------------------------------------------------------------# # Terminate with an error sub Abort { print "@_\n"; exit 1; } # Generate a label and return it sub GenLabel { # Generate the label return sprintf ("L%06X", $LabelNum++); } # Make an output file name from an input file name sub GetOutName { # Input name is parameter local $InName = @_[0]; # Create the output file name from the input file name if ($InName =~ /^(.+)\.([^\.\/]*)$/) { return "$1.html"; } else { return "$InName.html"; } } # Print the document header sub DocHeader { local $OUT = shift (@_); local $Asm = shift (@_); print $OUT <<"EOF"; SDSL Traffic


$Asm




EOF
}

# Print the document footer
sub DocFooter {
    local $OUT  = shift (@_);
    local $Name	= shift (@_);

    # Get the current date and time
    $Today = localtime;

    print $OUT <<"EOF";



\"Valid $Name; generated on $Today by ca65html
uz\@cc65.org
EOF } # Remove illegal characters from a string sub Cleanup { local $S = shift (@_); $S =~ s/&/&/g; $S =~ s//>/g; $S =~ s/\"/"/g; return $S; } #-----------------------------------------------------------------------------# # Pass 1 # # ----------------------------------------------------------------------------# # Process1: Read one file for the first time. sub Process1 { # Variables local $Line; local $Id; # Filename is parameter local $InName = shift(@_); # Create the output file name from the input file name local $OutName = GetOutName ($InName); # Current cheap local label prefix is empty local $CheapPrefix = ""; # Open a the input file open (INPUT, "<$InName") or Abort ("Cannot open $InName"); # Read and process all lines from the file while ($Line = ) { # Remove the newline chop ($Line); # Check for a label if ($Line =~ /^\s*(\@?)([_a-zA-Z][_\w]*)\s*(:|=)/) { # Is this a local label? if ($1 eq "\@") { # Use the prefix $Id = "$CheapPrefix$1$2"; } else { # Use as is $Id = $2; # Remember the id as new cheap local prefix $CheapPrefix = $Id; } # Remember the label $Labels{$InName}{$Id} = GenLabel(); # Check for an import statement } elsif ($Line =~ /^\s*(\.import|\.importzp|.proc)\s+(.*?)(\s*)(;.*$|$)/) { # Split into a list of identifiers local @Ids = split (/\s*,\s*/, $2); for my $Id (@Ids) { $Labels{$InName}{$Id} = GenLabel(); } # Check for an export statement } elsif ($Line =~ /^\s*(\.export|\.exportzp)\s+(.*?)(\s*)(;.*$|$)/) { # Split into a list of identifiers local @Ids = split (/\s*,\s*/, $2); for my $Id (@Ids) { $Exports{$Id} = sprintf ("%s#%s", $OutName, GenLabel()); } } } # Close the input file close (INPUT); } # Pass1: Read all files for the first time. sub Pass1 { # List of new files we found local @NewFiles = (); # Walk over the files for my $InName (@_) { # Process one file Process1 ($InName); } } #-----------------------------------------------------------------------------# # Pass 2 # # ----------------------------------------------------------------------------# # Process2: Read one file the second time. sub Process2 { # Variables local $Base; local $Ext; local $Line; local $OutLine; local $Id; local $Label; local $Operand; local $Comment; # Input file is parameter local $InName = shift(@_); # Create the output file name from the input file name local $OutName = GetOutName ($InName); # Current cheap local label prefix is empty local $CheapPrefix = ""; # Open a the input file open (INPUT, "<$InName") or Abort ("Cannot open $InName"); # Open the output file and print the HTML header open (OUTPUT, ">$OutName") or Abort ("Cannot open $OutName"); DocHeader (OUTPUT, $InName); # The instructions that will have hyperlinks if a label is used local $Ins = "adc|add|and|bcc|bcs|beq|bit|bmi|bne|bpl|bcv|bvs|cmp|cpx|cpy|dec|". "eor|inc|jmp|jsr|lda|ldx|ldy|ora|rol|sbc|sta|stx|sty|sub|"; # Read the input file, replacing references by hyperlinks and mark # labels as link targets. while ($Line = ) { # Remove the newline chop ($Line); # Clear the output line $OutLine = ""; # Check for a label. If we have one, process it and remove it # from the line if ($Line =~ /^\s*?(\@?)([_a-zA-Z][_\w]*)(\s*)(:|=)(.*)$/) { # Is this a local label? if ("$1" eq "\@") { # Use the prefix $Id = "$CheapPrefix$1$2"; } else { # Use as is $Id = $2; # Remember the id as new cheap local prefix $CheapPrefix = $Id; } # Get the label for the id $Label = $Labels{$InName}{$Id}; # Print the label with a tag $OutLine .= sprintf ("%s%s%s%s", $Label, $1, $2, $3, $4); # Use the remainder for line $Line = $5; } # Print any leading whitespace and remove it, so we don't have to # care about whitespace below. if ($Line =~ /^(\s+)(.*)$/) { $OutLine .= "$1"; $Line = $2; } # Handle the import statements if ($Line =~ /^(\.import|\.importzp)(\s+)(.*)$/) { # Print any fixed stuff from the line and remove it $OutLine .= "$1$2"; $Line = $3; # Print all identifiers if there are any while ($Line =~ /^([_a-zA-Z][_\w]*)(.*)$/) { # Identifier is $1, remainder is $2 $Id = $1; $Line = $2; # Variable to assemble HTML representation local $Item = $Id; # If we have an export for this import, add a link to this # export definition if (exists ($Exports{$Id})) { $Label = $Exports{$Id}; $Item = sprintf ("%s", $Label, $Item); } # Make this import a link target if (exists ($Labels{$InName}{$Id})) { $Label = $Labels{$InName}{$1}; $Item = sprintf ("%s", $Label, $Item); } # Add the HTML stuff to the output line $OutLine .= $Item; # Check if another identifier follows if ($Line =~ /^(\s*),(\s*)(.*)$/) { $OutLine .= "$1,$2"; $Line = $3; } else { last; } } # Add an remainder if there is one $OutLine .= Cleanup ($Line); # Handle export statements } elsif ($Line =~ /^(\.export|\.exportzp)(\s+)(.*)$/) { # Print the command the and white space $OutLine .= "$1$2"; $Line = $3; # Print all identifiers if there are any while ($Line =~ /^([_a-zA-Z][_\w]*)(.*)$/) { # Identifier is $1, remainder is $2 $Id = $1; $Line = $2; # Variable to assemble HTML representation local $Item = $Id; # If we have a definition for this export in this file, add # a link to the definition. if (exists ($Labels{$InName}{$1})) { $Label = $Labels{$InName}{$1}; $Item = sprintf ("%s", $Label, $Item); } # If we have this identifier in the list of exports, add a # jump target for the export. if (exists ($Exports{$Id})) { $Label = $Exports{$Id}; # Be sure to use only the label part $Label =~ s/^(.*#)(.*)$/$2/; $Item = sprintf ("%s", $Label, $Item); } # Add the HTML stuff to the output line $OutLine .= $Item; # Check if another identifier follows if ($Line =~ /^(\s*),(\s*)(.*)$/) { $OutLine .= "$1,$2"; $Line = $3; } else { last; } } # Add an remainder if there is one $OutLine .= Cleanup ($Line); # Check for .addr and .word } elsif ($Line =~ /^(\.addr|\.word)(\s+)(.*)$/) { # Print the command the and white space $OutLine .= "$1$2"; $Line = $3; # Print all identifiers if there are any while ($Line =~ /^([_a-zA-Z][_\w]*)(.*)$/) { if (exists ($Labels{$InName}{$1})) { $Label = $Labels{$InName}{$1}; $OutLine .= sprintf ("%s", $Label, $1); } else { $OutLine .= "$1"; } $Line = $2; if ($Line =~ /^(\s*),(\s*)(.*)$/) { $OutLine .= "$1,$2"; $Line = $3; } else { last; } } # Add an remainder if there is one $OutLine .= Cleanup ($Line); # Check for any legal instruction } elsif ($Line =~ /^($Ins)(\s+)(.*?)(\s*)(;.*$|$)/) { # Print the instruction and white space $OutLine .= "$1$2"; # Remember the remaining parts $Operand = $3; $Comment = Cleanup ("$4$5"); # Check for the first identifier in the operand and replace it # by a hyperlink if ($Operand =~ /^([^_a-zA-Z]*?)(\@?)([_a-zA-Z][_\w]*)(.*)$/) { # Is this a local label? if ("$2" eq "\@") { # Use the prefix $Id = "$CheapPrefix$2$3"; } else { # Use as is $Id = $3; } # Do we have a label for this id? if (exists ($Labels{$InName}{$Id})) { $Label = $Labels{$InName}{$Id}; $Operand = sprintf ("%s%s%s%s", Cleanup($1), $Label, $2, $3, Cleanup ($4)); } } # Reassemble and print the line $OutLine .= "$Operand$Comment"; } else { # Nothing known - print the line $OutLine .= Cleanup ($Line); } # Print the result print OUTPUT "$OutLine\n"; } # Print the HTML footer DocFooter (OUTPUT, $OutName); # Close the files close (INPUT); close (OUTPUT); } # Pass2: Read all files the second time. sub Pass2 { # Walk over the files for my $InName (@_) { # Process one file Process2 ($InName); } } # ---------------------------------------------------------- # Code # ---------------------------------------------------------- # Get the arguments #if ($#ARGV != 0) { # printf STDERR "Usage: %s asm-file\n", $ARGV[0]; # exit (1); #} # Pass1 (@ARGV); Pass2 (@ARGV); # Done exit 0;