#!/usr/bin/perl5 -w ### Name: c2js ### Author: Douglas Sweetser ### sweetser@TheWorld.com ### program description my $help_string = < */ /* */ subroutines declarations: *return on separate line name(vars) { at start of next 1 declaration per line initial values defined, such as "double d = 3;" object* constructObject(var) { for new object creation HELP ### algorithm # reads in files sequentially # translates to javascript # does not write (many) unused library functions ### bugs, upgrades # may require much maintenance, arg! ### modules use strict; use English; use Getopt::Long; $Getopt::Long::autoabbrev = 1; # use 1 letter $Getopt::Long::ignorecase = 0; # be case sensitive please ### variables my($program, @programs); # The code, array of the code $program = ""; my($function_name, $function_flag); $function_flag = 1; my($function, @functions, %functions); # used in the code my($library, $missing_functions); # missing from javascript $library = ""; my($lib); # small library my($file, $file_in, $file_out); my($line); my($help_flag); ### prototypes sub _get_data (); # command line processing sub translate_c_2_js ($); # translates c to javascript sub mini_library ($$); # returns only library functions used sub _get_functions ($$); # gets functions based on XML tags ### main # get data from command line _get_data(); # Translate from c to javascript library, programs $file_in = "Qlib.c"; open(FILE_IN, $file_in) || die ("could not open $file_in: $!"); while() { $library .= $_; } close(FILE_IN); $library = translate_c_2_js($library); # go through each file for $file (@ARGV) { my $temp = ""; # add each line to $program open(FILE_IN, $file) || die ("could not open $file: $!"); while() { $temp .= $_; } close(FILE_IN); $program .= translate_c_2_js($temp); } # TESTING:{print "$program is: $program\n"}; # make a unique list of all functions used (@functions) = $program =~ /(\w*)\(/gm; foreach $function (@functions) { $functions{$function} = ""; } # math functions in C, not found in javascript $missing_functions = < */ function sinh(Z) { return (Math.exp(Z) - Math.exp(-Z))/2; } /* */ /* */ function cosh(Z) { return (Math.exp(Z) + Math.exp(-Z))/2; } /* */ /* */ function tanh(Z) { return sinh(Z) / cosh(Z); } /* */ FUNC # add to javascript library $library .= $missing_functions; # open file for output $file_out = $ARGV[0] . ".js"; open(FILE_OUT, ">$file_out"); # process lines individually @programs = split("\n", $program); for $line (@programs) { print FILE_OUT $line, "\n"; # at main, plug in library if ($line =~ /main\(\)/) { $lib = mini_library($library, \%functions); print FILE_OUT $lib; } } close(FILE_OUT); ### signals exit(0); ### subroutines # Get data from the command line # sub _get_data () { GetOptions("help" => \$help_flag); # print the help message if ($help_flag) { print ("$help_string"); exit(0); } } # Given: # a library as a string # a pointer to a hash of used functions # Returns a string of only those functions used # NOTE: requires XML tags # sub mini_library ($$) { ### algorithm # calls _get_functions with same arguments # determines unique internal functions # calls _get_functions again ### variables my ($input); my ($func, @funcs, %functions_used, %functions_internal); my $result = ""; my ($temp); # assign $input = $_[0]; %functions_used = %{$_[1]}; # include functions in the program to the result $result .= _get_functions ($input, \%functions_used) . "\n"; # add internally used library functions # trying to avoid function foo by look for # (function(, function(, = function( and , function( @funcs = $input =~ /\((\w{2,})\(/gm; push @funcs, $result =~ /^\s+(\w{2,})\(/gm; push @funcs, $result =~ /\=\s+(\w{2,})\(/gm; push @funcs, $result =~ /\,\s+(\w{2,})\(/gm; # find unique internal functions foreach $func (@funcs) { $functions_internal{$func} = "" unless (exists $functions_used{$func}); } # include internal functions in the library to the result $result .= _get_functions ($input, \%functions_internal) . "\n"; # return a string of code return $result; } # Given: # a library as a string # a pointer to a hash of used functions # Returns a string of only those functions used # NOTE: requires XML tags # sub _get_functions ($$) { ### algorithm # loops through code one line at a time # sets flag based on XML tag # adds function if in hash passed in ### variables my($input, $library_line, @library_lines); my(%functions_used); my $result = ""; # assign $input = $_[0]; %functions_used = %{$_[1]}; # go through lines 1 by 1 @library_lines = split("\n", $input); foreach $library_line (@library_lines) { # get the function name from XML tag ($function_name) = $library_line =~ /function name=\"(\w*)\"/; # set a flag if it exists $function_flag = 1 if ($function_name and exists($functions_used{$function_name})); $function_name = ""; #print $result .= $library_line . "\n" if($function_flag); #reset if ($library_line =~ /<\/function/) { $function_flag = 0; $result .= "\n"; } } # return a string of functions return $result; } # given a string in C # returns a translated string # sub translate_c_2_js($) { ### algorithm # regular expression replacement for language differences # go through line by line for object creation code, printing ### variables my ($c, @c_lines); my $this = ""; my $line = ""; my $scope_flag = 0; # assign $c = $_[0]; # replacements from C to javascript # start with most specific changes, then go to general stuff # stuff at start of files $c =~ s/\#include.+//g; # remove include statements $c =~ s/\#define\s+(\w+)\s+([\w.]+)/$1 = $2\;/ig; $c =~ s/(void main\(\))/\/\* $1 \*\//g; # comment out void mains # subroutines $c =~ s/^\w+\*?\s?$//mg; # subroutine return declarations $c =~ s/(^\w+\()/function $1/mg; # convert subroutines into functions # declarations $c =~ s/Q \*\w+\;//g; $c =~ s/Q //g; $c =~ s/double //g; # pointers $c =~ s/-\>/\./g; $c =~ s/\\n/\/g; $c =~ s/\*(\w)/$1/g; $c =~ s/\&(\w)/$1/g; # objects $c =~ s/construct//g; $c =~ s/return Q\(/return new Q\(/g; $c =~ s/(\w+ \= )(\w+\([\d\, \)\;]+\s?)$/var $1new $2/gm; #printing $c =~ s/\%\w*\s*//g; # translate C's math functions into javascript Math.methods $c =~ s/( |\()(abs\()/$1Math.$2/g; $c =~ s/( |\()(acos\()/$1Math.$2/g; $c =~ s/( |\()(asin\()/$1Math.$2/g; $c =~ s/( |\()(atan\()/$1Math.$2/g; $c =~ s/( |\()(atan2\()/$1Math.$2/g; $c =~ s/( |\()(ceil\()/$1Math.$2/g; $c =~ s/( |\()(cos\()/$1Math.$2/g; $c =~ s/( |\()(exp\()/$1Math.$2/g; $c =~ s/( |\()(floor\()/$1Math.$2/g; $c =~ s/( |\()(log\()/$1Math.$2/g; $c =~ s/( |\()(max\()/$1Math.$2/g; $c =~ s/( |\()(min\()/$1Math.$2/g; $c =~ s/( |\()(pow\()/$1Math.$2/g; $c =~ s/( |\()(random\()/$1Math.$2/g; $c =~ s/( |\()(round\()/$1Math.$2/g; $c =~ s/( |\()(sin\()/$1Math.$2/g; $c =~ s/( |\()(sqrt\()/$1Math.$2/g; $c =~ s/( |\()(tan\()/$1Math.$2/g; # must search out object creation, use this @c_lines = split("\n", $c); # reset $c = ""; # cycle through code one line at a time for $line (@c_lines) { # find code with malloc, set a flag if ($line =~ /.*malloc.*/) { ($this) = $line =~ /(\w+)\s+\=/; $line = ""; $scope_flag = 1; } # use this for objects $line =~ s/\b$this\b/this/g if ($this && $scope_flag); # unset the flag $scope_flag = 0 if ($line =~ /\}/); # modify printf statments if ($line =~ /printf/) { $line =~ s/printf/document\.write/; # Buggy - how to put in spaces in document.write? $line =~ s/,/, ' ',/g; } $c .= $line . "\n"; } # return string with translated code return $c; } ### perldoc =pod =head1 NAME c2js - converse quaternion c programs to javascript =head1 SYNOPSIS B [-help] programs.c(s) =head1 DESCRIPTION Can directly convert quaternion.c programs into javascript =head1 OPTIONS =item I<-help> usage: c2js [-help] program.c(s) translates quaternion c programs to javascript given file(s) output is firstfile.c.js very sensitive to syntax! must use conventions found in Qlib.c Uses XML syntax around subroutines /* */ /* */ subroutines declarations: *return - on separate line name(vars) { - at start of next 1 declaration per line initial values defined, such as "double d = 3;" object* constructObject(var) { for new object creation =head1 AUTHOR Doug Sweetser, sweetser@TheWorld.com =head1 LICENSE GPL - GNU General Public License, version 2 =cut