-#!/usr/bin/perl
+#!/usr/bin/perl -w
+
# keil2sdcc.pl
-# converts Keil compatible header files to sdcc-compatible format
-# call (path)/keil2sdcc.pl keil_file_name sdcc_file_name
+# Scott Bronson
+# 22 June 2003
+
+
+# usage (UNIX):
+# perl keil2sdcc.pl < keil_header.h > sdcc_header.h
+# or
+# perl keil2sdcc.pl keil_header.h > sdcc_header.h
#
-# Bela Torok - bela.torok@kssg.ch
-# Version: June 2001
+# usage (Windows):
+# perl keil2sdcc.pl keil_header.h > sdcc_header.h
#
-# Limitation: Keil-style sfr and sbit definitions should begin
-# in the first column!
#
+# keil_header.h and sdcc_header.h must not be the same file since
+# most shells overwrite the output file before opening the input file.
-$keil_file = $ARGV[0];
-$sdcc_file = $ARGV[1];
-if (open (KEIL_FILE , "<" . $keil_file)) {
-# printf("Opening file: %s for output!\n", $keil_file);
-} else {
- printf("Cannot open file: %s !\n", $keil_file);
- exit (0);
-}
+# This script converts Keil-style header files to SDCC. It tries to
+# be pedantic so don't be surprised if you need to munge it a bit to
+# get it to work. On the other hand, it doesn't fully parse the C
+# file (for obvious reasons).
-if (open (SDCC_FILE ,">" . $sdcc_file)) {
-# printf("Opening file: %s for output!\n", $sdcc_file);
-} else {
- printf("Cannot open file: %s !\n", $sdcc_file);
- exit (0);
-}
+# It takes the Keil header file either as an argument or on
+# stdin and it produces the output on stdout.
-while ($input_buffer = <KEIL_FILE>) {
-
- if( substr($input_buffer, 0, 3) eq 'sfr')
- {
- &convert( substr($input_buffer, 4) );
- print SDCC_FILE "sfr at", $value, " ", $name, ";", $comment;
- }
- elsif( substr($input_buffer, 0, 4) eq 'sbit')
- {
- &convert( substr($input_buffer, 5) );
- print SDCC_FILE "sbit at", $value, " ", $name, ";", $comment;
- }
- else {
- print SDCC_FILE $input_buffer;
- }
+# This script is inspired by keil2sdcc.pl by Bela Torok but a lot
+# more pedantic.
-}
+use strict;
-close (KEIL_FILE);
-close (SDCC_FILE);
-exit (0);
-
-sub convert
+while(<>)
{
- local($arg) = @_;
-
- ($command, $comment) = split(';' , $arg);
-
- ($name, $value) = split('=' , $command);
-
+ s/\r//g; # remove DOS line endings if necessary
+
+ # external register (kind of a weird format)
+ #
+ # in: EXTERN xdata volatile BYTE GPIF_WAVE_DATA _AT_ 0xE400;
+ # out: EXTERN xdata at 0xE400 volatile BYTE GPIF_WAVE_DATA;
+ # $1: leading whitespace
+ # $2: variable name
+ # $3: variable location
+ # $4: trailing comments, etc.
+
+ if(/^(\s*)EXTERN\s*xdata\s*volatile\s*BYTE\s*(\w+(?:\s*\[\s*\d+\s*\])?)\s+_AT_\s*([^;]+);(.*)$/) {
+ print "$1EXTERN xdata at $3 volatile BYTE $2;$4\n";
+ next;
+ }
+
+ # sfr statement
+ #
+ # in: sfr IOA = 0x80;
+ # out: sfr at 0x80 IOA;
+ # $1: leading whitespace
+ # $2: variable name
+ # $3: variable location
+ # $4: trailing comments, etc.
+
+ if(/^(\s*)sfr\s*(\w+)\s*=\s*([^;]+);(.*)$/) {
+ print "$1sfr at $3 $2;$4\n";
+ next;
+ }
+
+ # sbit statement
+ #
+ # in: sbit SEL = 0x86+0;
+ # out: sbit at 0x86+0 SEL;
+ # $1: leading whitespace
+ # $2: variable name
+ # $3: variable location
+ # $4: trailing comments, etc.
+
+ if(/^(\s*)sbit\s*(\w+)\s*=\s*([^;]+);(.*)$/) {
+ print "$1sbit at $3 $2;$4\n";
+ next;
+ }
+
+
+
+ # entire line is a C++ comment, output it unchanged.
+ if(/^(\s*)\/\/(.*)$/) {
+ print "$1//$2\n";
+ next;
+ }
+
+ # C comment, slurp lines until the close comment and output it unchanged.
+ if(/^(\s*)\/\*(.*)$/) {
+ my($ws,$cmt) = ($1,"$2\n");
+ $cmt .= <> while $cmt !~ /\*\/\s*$/;
+ $cmt =~ s/\r//g;
+ print "$ws/*$cmt";
+ next;
+ }
+
+ # preprocessor statement (whitespace followed by '#'), don't change
+ if(/^(\s*)\#(.*)$/) {
+ print "$1#$2\n";
+ next;
+ }
+
+ # blank line, don't change
+ if(/^(\s*)$/) {
+ print "\n";
+ next;
+ }
+
+ chomp;
+ die "Unconvertable line: \"$_\"\n";
}
-
-
-
-
-
-
-
-
-
-
-