From 35e22de2c2dd9cd3b20cd60f91b33ea62be0044d Mon Sep 17 00:00:00 2001 From: cuz Date: Wed, 6 Dec 2000 10:10:52 +0000 Subject: [PATCH] Handle multiple files and cheap local labels git-svn-id: svn://svn.cc65.org/cc65/trunk@559 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- src/ca65html/ca65html | 562 ++++++++++++++++++++++++++++++------------ 1 file changed, 411 insertions(+), 151 deletions(-) diff --git a/src/ca65html/ca65html b/src/ca65html/ca65html index 6961c8eb4..297502676 100755 --- a/src/ca65html/ca65html +++ b/src/ca65html/ca65html @@ -1,16 +1,55 @@ #!/usr/bin/perl - -# -# Convert a ca65 source into HTML -# -# Ullrich von Bassewitz, 05.12.2000 -# - - - -# ---------------------------------------------------------- -# Helper functions -# ---------------------------------------------------------- +############################################################################### +# # +# 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 # +# ----------------------------------------------------------------------------# @@ -20,6 +59,26 @@ sub Abort { 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 (@_); @@ -79,182 +138,383 @@ sub Cleanup { -# ---------------------------------------------------------- -# Code -# ---------------------------------------------------------- +#-----------------------------------------------------------------------------# +# 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()); + } -# Get the arguments -if ($#ARGV != 1) { - printf STDERR "Usage: %s asm-file output-file\n", $ARGV[0]; - exit (1); -} -$ASM = shift (@ARGV); -$OUT = shift (@ARGV); - -# Open a the input file -open (ASM, "<$ASM") or Abort ("Cannot open $ASM"); - -# Read all lines and remember labels -$LNum = 1; -%Label = (); -while ($Line = ) { - - # Remove the newline - chop ($Line); - - # Check for a label - if ($Line =~ /^\s*([_\w][_\w\d]*)\s*(:|=)/) { - $Label { $1 } = $LNum++; - } elsif ($Line =~ /^\s*(\.import|\.importzp|.proc)\s+(.*?)(\s*)(;.*$|$)/) { - @L = split (/\s*,\s*/, $2); - for my $Id (@L) { - $Label { $Id } = $LNum++; } } + + # Close the input file + close (INPUT); } -# Reset the file pointer to the beginning -seek (ASM, 0, 0); -# Open the output file and print the HTML header -open (OUT, ">$OUT") or Abort ("Cannot open $OUT"); -DocHeader (OUT, $ASM); -# The instructions that will have hyperlinks if a label is used -$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|"; +# Pass1: Read all files for the first time. +sub Pass1 { -# Read the input file again, replacing references by hyperlinks and mark -# labels as link targets. -while ($Line = ) { + # List of new files we found + local @NewFiles = (); - # Remove the newline - chop ($Line); + # Walk over the files + for my $InName (@_) { - # Clear the output line - $OutLine = ""; + # Process one file + Process1 ($InName); - # Check for and ignore a local label - if ($Line =~ /^(\s*\@[_\w][_\w\d]*\s*:)(.*)$/) { - # Print the label - $OutLine .= "$1"; - # Use the remainder for line - $Line = $2; } +} - # Check for a label, if we have one, remove it from the line - if ($Line =~ /^\s*([_\w][_\w\d]*)(\s*)(:|=)(.*)$/) { - # Print the label with a tag - $OutLine .= sprintf ("%s%s%s", $Label { $1 }, $1, $2, $3); - # Use the remainder for line - $Line = $4; - } - # Print any leading whitespace - if ($Line =~ /^(\s+)(.*)$/) { - $OutLine .= "$1"; - $Line = $2; - } - # Handle the import statements - if ($Line =~ /^(\.import|\.importzp|.proc|)(\s+)(.*)$/) { - $OutLine .= "$1$2"; - $Line = $3; +#-----------------------------------------------------------------------------# +# Pass 2 # +# ----------------------------------------------------------------------------# - # Print all identifiers if there are any - while ($Line =~ /^([_\w][_\w\d]*)(.*)$/) { - $Num = $Label { $1 }; - if ($Num != 0) { - $OutLine .= sprintf ("%s", $Num, $1); - } else { - $OutLine .= "$1"; - } - $Line = $2; - if ($Line =~ /^(\s*),(\s*)(.*)$/) { - $OutLine .= "$1,$2"; - $Line = $3; + + +# 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 { - last; + # 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; } - # Add an remainder if there is one - $OutLine .= Cleanup ($Line); + # Print any leading whitespace and remove it, so we don't have to + # care about whitespace below. + if ($Line =~ /^(\s+)(.*)$/) { + $OutLine .= "$1"; + $Line = $2; + } - # Check for control commands that may reference lists of labels - } elsif ($Line =~ /^(\.addr|\.word|\.export)(\s+)(.*)$/) { + # 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; + } + } - # Print the command the and white space - $OutLine .= "$1$2"; - $Line = $3; + # 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; + } + } - # Print all identifiers if there are any - while ($Line =~ /^([_\w][_\w\d]*)(.*)$/) { - $Num = $Label { $1 }; - if ($Num != 0) { - $OutLine .= sprintf ("%s", $Num, $1); - } else { - $OutLine .= "$1"; + # 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; + } } - $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)); + } + } - } - # Add an remainder if there is one - $OutLine .= Cleanup ($Line); - - # Check for any legal instruction - } elsif ($Line =~ /^($Ins)(\s+)(.*)$/) { - - # Print the instruction and white space - $OutLine .= "$1$2"; - $Line = $3; - - # Check for a comment or traling whitespace and separate it - if ($Line =~ /^(.*?)(\s*)(;.*)$/) { - $Line = $1; - $Comment = "$2$3"; - } elsif ($Line =~ /^(.*?)(\s*)$/) { - $Line = $1; - $Comment = $2; - } else { - $Comment = ""; - } + # Reassemble and print the line + $OutLine .= "$Operand$Comment"; + + } else { + + # Nothing known - print the line + $OutLine .= Cleanup ($Line); - # Check for the first identifier and replace it by a hyperlink - if ($Line =~ /^([^_a-zA-Z]*)([_a-zA-Z][_\w]*)(.*)$/ && $Label { $2 } != 0) { - $Line = sprintf ("%s%s%s", - Cleanup ($1), $Label { $2 }, $2, Cleanup ($3)); } - # Clean the comment - $Comment = Cleanup ($Comment); + # Print the result + print OUTPUT "$OutLine\n"; + } - # Reassemble and print the line - $OutLine .= "$Line$Comment"; + # Print the HTML footer + DocFooter (OUTPUT, $OutName); - } else { + # Close the files + close (INPUT); + close (OUTPUT); +} - # Nothing known - print the line - $OutLine .= Cleanup ($Line); - } - # Print the result - print OUT "$OutLine\n"; +# Pass2: Read all files the second time. +sub Pass2 { + + # Walk over the files + for my $InName (@_) { + + # Process one file + Process2 ($InName); + + } } -# Print the HTML footer -DocFooter (OUT, $OUT); -# Close the files -close (ASM); -close (OUT); + +# ---------------------------------------------------------- +# 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; -- 2.39.5