#! /local/bin/perl -s # Transformer.pl version 0.45, 24.03.99 # Copyright 1999 Ole Dahle # Purpose: Rewrite SDL diagrams (in PR/CIF format) to make them more readable # Usage: perl transfomer.pl [-warn] [-insert] infile [outfile] # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #Preferences: $infile = "phase3.sdl"; $showWarnings = 0; $insertComments = 0; $removeInvisibleJoins = 1; $flowsPerPage = 4; # Number of flows allowed on a page $flowSpacing = 380; # Number of pixels between each flow $pageWidth = 1500; $pageHeight = 2200; #Look for command line options if($warn != 0) {$showWarnings = 0;} if($insert != 0) {$insertComments = 0;} $firstfile = 1; foreach (@ARGV) { if(!(/^-/) && !$firstfile) {$outfile = $_;} if(!(/^-/) && $firstfile) {$infile = $_; $firstfile = 0;} } if($outfile eq "") {$outfile = "fixed_$infile";} if($insertComments) {$flowsPerPage = $flowsPerPage/2; $flowSpacing = $flowSpacing *2;} print "$infile $outfile $showWarnings $insertComments space: $flowSpacing\n"; #Global variables @sdlfile; #Array that contains the SDL file $i = $j = 0; #Counters $x= $y = 0; #Position variables $statePosX = 0; $statePosY = 0; # Position of state symbol #Initialize: Open infile, read it into the sdlfile array. print "Transformer starting\n"; open(INPUT,$infile) or die("Could not open input file $infile.\n"); print "opening $infile\n"; @sdlfile = ; close(INPUT); #Perform transformations if($insertComments) { &insertTextExtensions; &makeSignalTextExtension; } if($removeInvisibleJoins) { &removeInvisibleJoins;} &expandConnections; &stateOnNewPage; &alignPages; &resolvePageOverflow; &alignNextstates; &removeEmptyPages; if($showWarnings) { &warnShortNames; &warnBranchOnDecision; } #Write transformed SDL to file open(OUTPUT,">$outfile") or die("Could not open output file $outfile.\n"); print "Writing to $outfile.\n"; foreach $outline (@sdlfile) { print OUTPUT "$outline"; } close(OUTPUT); #End of program #----------- Subroutines representing transformational rules below-----------# sub expandConnections { local(@connections) = (); local(@joins) = (); local(%definition) = 0; local($numberOfConnections) = 0; local($invisibleJoins) = 0; local(%used) = (); local($currentState); #Scan trough sdlfile, find all connections; $i = 0; while($i< @sdlfile) { if($sdlfile[$i] =~ /^join (\w+)/i) #Count occurences of join { #Lowercase connection name, works with norwegian characters: $temp = $1; $temp =~ tr/A-ZÆØÅ/a-zæøå/; #Count auto-generated, graphical connections separately if($temp =~ /^grst\d+/) {$invisibleJoins++;} else {$used{$temp}++;} } $i++; } @temp = %used; $numberOf = @temp; $numberOf = $numberOf/2; print "There are $numberOf connections and $invisibleJoins invisible joins used in the file.\n"; # Treat each connection separately foreach $con (reverse sort keys(%used)) { print "Connection $con was used $used{$con} times. Do you want to:\n"; print "Expand all occurences? (1)\n"; print "Expand selected occurences? (2)\n"; print "Turn it into a procedure? (3)\n"; print "Do nothing? (Any other key)\n"; $answer = <>; #print "$answer \n"; if($answer ==1 || $answer ==2 || $answer ==1) { #Rescan sdlfile, since joins-wihtin-joins may have been expanded, and # increased the number of joins. $i = 0; foreach $temp( keys (%used)) {$used{$temp} = 0;} while($i< @sdlfile) {if($sdlfile[$i] =~ /^join (\w+)/i) #Count occurences of join { #Lowercase connection name, works with norwegian characters: $temp = $1; $temp =~ tr/A-ZÆØÅ/a-zæøå/; #Skip auto-generated, graphical connections if(!($temp =~ /^grst\d+/)) {$used{$temp}++;} } $i++; } } # --- Expand connection --- if($answer == 1 || $answer == 2) { #Finding the definition of the connection $i = 0; until(($sdlfile[$i] =~ /^connection $con/i) || $i == @sdlfile) {$i++}; if($i == @sdlfile) {print "Couldn't find the definition of $con!\n";} else { $def = $i+2; $i = 0; $expandedJoins = 0; #Enter do-it-all or selected-only mode if($answer == 1) {$doit = 1;} else {$doit = 0; } while($i < @sdlfile) { # Keep track of wich state we're in if($sdlfile[$i] =~ /^state (.+)(;|\n)/i) {$currentState = $1;} if($answer == 2 &&$sdlfile[$i] =~ /^join $con/i) { #Ask if in selected-only mode print "Found an occurence of $con in state $currentState.\n"; print "Expand it? (y/n) "; $expand = <>; if($expand =~ /^y/i) {$doit = 1} } if($sdlfile[$i] =~ /^join $con/i && $doit) { $sdlfile[$i-1] =~ /^\/\* CIF Join \((\d+),(\d+)\)/i; #print "$1 $2 $sdlfile[$i-1]"; $x=$1; $y=$2; print "Replacing an occurence of join $con in state $currentState.\n"; splice(@sdlfile,$i-1,2); if($def > $i) {$def -= 2;} #print "Definition at $def, pointer at $i\n"; $k = $def; $i--; #Find the label, find the coordinates $tmp = $k; until($sdlfile[$tmp] =~ /\/\* CIF/i && $sdlfile[$tmp] !~ /(Line|comment)/i) { # Lines and comments are not at the same coordinates as the flow $tmp++; } $sdlfile[$tmp] =~ /\((\d+),(\d+)\)/; #print "$1,$2 $sdlfile[$tmp]"; # Calculating offset: $x = $1+50 - $x; $y = $2 - $y; #print "Offset: x: $x y: $y\n"; if($sdlfile[$k] =~ /^\/\* CIF Line/i) {$k++;} # Skip first line until($sdlfile[$k] =~ /^\/\* CIF End Label/i) { # Treat comments to the connection label specially: if(($sdlfile[$k-1] =~ /^connection/i) && ($sdlfile[$k] =~ /\/\* CIF Comment \((\d+),(\d+)/i)) { #print "Moving comment...\n"; $tempx = $1-$x; $tempy = $2-$y; # Create Textbox instead of comment splice(@sdlfile,$i,0,"/* CIF Text ($tempx,$tempy),(300,400) */\n"); $i++; $k++; if($def > $i) {$def++; $k++;} splice(@sdlfile,$i,0,"/* Comment moved by Transformer:\n"); $i++; if($def > $i) {$def++; $k++;} # Skip the line to the old comment if($sdlfile[$k] =~ /\/\* CIF Line/i) {$k++;} # Remove "comment '" from first line splice(@sdlfile,$i,0,"$sdlfile[$k]"); print "Should be old comment: $sdlfile[$i]"; $sdlfile[$i] =~ s/comment '//i; $i++; $k++; if($def > $i) {$def++; $k++;} # Put the rest of the comment in the box until($sdlfile[$k] =~ /^(;|:)/) # ':' is wrong, but used sometimes? { splice(@sdlfile,$i,0,"$sdlfile[$k]"); #$sdlfile[$i] =~ s/\n/\*\/\n/; $i++; $k++; if($def > $i) {$def++; $k++;} } # Insert text box end instead of ';' print "$sdlfile[$k]"; $sdlfile[$i-1] =~ s/'/\*\//; print "$sdlfile[$i-1]"; splice(@sdlfile,$i,0,"/* CIF End Text */\n"); $i++; $k++; if($def > $i) {$def++; $k++;} } else {splice(@sdlfile,$i,0,$sdlfile[$k]); # In some CIF statements, only the first (x,y) pair must be changed, # since the second (x,y) defines the size of the symbol. if($sdlfile[$i] =~ /\/\* CIF (Label|Join|Comment|Text) /i) { $sdlfile[$i]=~ s/\((\d+)/$1-$x/e; # Substitute '(x' with x minus offset $sdlfile[$i]=~ s/(\d+)\)/$1-$y/e; # Substitute 'y)' with y minus offset $sdlfile[$i]=~ s/(\d+),(\d+)/\($1,$2\)/; # Put the parantheses back in } elsif($sdlfile[$i] =~ /\/\* CIF/) { $sdlfile[$i]=~ s/\((\d+)/$1-$x/ge; # Substitute '(x' with x minus offset $sdlfile[$i]=~ s/(\d+)\)/$1-$y/ge; # Substitute 'y)' with y minus offset $sdlfile[$i]=~ s/(\d+),(\d+)/\($1,$2\)/g; # Put the parantheses back in } #print "$sdlfile[$i]"; $i++; $k++; if($def > $i) {$def++; $k++;} } #End comment /normal line } #End inserting if($answer ==2) {$doit = 0;} #Don't expand next one without asking $expandedJoins++; } #End expanding occurence $i++; } #Deleting Connection definition if($expandedJoins == $used{$con}) #Only delete if all occurences were expanded { print "Deleting definition of $con\n"; $prevline = ""; $i = 0; until($sdlfile[$i] =~ /^connection $con/i) {$i++}; $i--; # Start with the CIF label-statement above the connection statement until($prevline =~ /^endconnection/i) { $prevline = $sdlfile[$i]; #print "$prevline"; splice(@sdlfile,$i,1); } } #End deleting definition } #End found definiton } #End expanding connection # --- Turn connection into procedure if($answer == 3) { #Finding the definition of the connection $i = 0; until(($sdlfile[$i] =~ /^connection $con/i) || $i == @sdlfile) {$i++}; if($i == @sdlfile) {print "Couldn't find the definition of $con!\n";} else { $def = $i+1; until(($sdlfile[$i] =~ /^endconnection $con/i) || $i == @sdlfile) { if($sdlfile[$i] =~ /^nextstate (\w+)/i) {$returns++; $returnState = $1;} $i++; } #@temp = %returns; $temp = @temp; if($returns > 2) { print "Connection $con has returns to more than one state!\n"; } else { #Open a file to put the new procedure in print "Creating procedure $con in separate file...\n"; $filename = "$con.sdl"; $overwrite = "n"; until(!(-e "$filename") || $overwrite =~ /^y/i) { print "$filename exists. OK to overwrite? (y/n)\n"; $overwrite = <>; if($overwrite =~ /^n/i) { print "Please supply a different name: "; $filename=<>; chop($filename); } } #Print the procedure to the file open(PROCFILE, ">$filename") or die("Failed to open $filename.\n"); print PROCFILE "/* CIF ProcedureDiagram */\n"; print PROCFILE "/* CIF Page 1 (1900,2300) */\n"; print PROCFILE "/* CIF Frame (0,0),(1900,2300) */\n"; print PROCFILE "/* CIF Specific SDT Version 1.0 */\n"; print PROCFILE "/* CIF Specific SDT Page 1 Scale 100 Grid (250,150) AutoNumbered */\n"; print PROCFILE "Procedure $con;\n"; print PROCFILE "/* CIF DefaultSize (200,100) */\n"; print PROCFILE "/* CIF CurrentPage 1 */\n"; print PROCFILE "/* CIF ProcedureStart (300,100) */\n"; print PROCFILE "start ;\n"; # Extract coordinates from label symbol, evaluate offset $j = $def; $sdlfile[$j-2] =~ /\/\* CIF Label \((\d+),(\d+)\)/i; #print "$sdlfile[$j-2]"; $x = $1-350; $y = $2-100; #print "x: $x y: $y $sdlfile[$j-2]\n"; # Print the connection to the file, alter all coordinates according to offset until($sdlfile[$j] =~ /^\/\* CIF End Label/i) { # Treat comments to the connection label specially: if(($sdlfile[$j-1] =~ /^connection/i) && ($sdlfile[$j] =~ /\/\* CIF Comment \((\d+),(\d+)/i)) { print "Moving comment...\n"; $tempx = $1-$x; $tempy = $2-$y; # Create Textbox instead of comment print PROCFILE "/* CIF Text ($tempx,$tempy),(300,400) */\n"; $j++; print PROCFILE "/* Comment moved by Transformer:\n"; # Skip the line to the old comment if($sdlfile[$j] =~ /\/\* CIF Line/i) {$j++;} # Remove "comment '" from first line print "Should be old comment: $sdlfile[$i]"; $sdlfile[$j] =~ s/comment '//i; $sdlfile[$j] =~ s/'\n/\*\/\n/; # If it's also the last print PROCFILE "$sdlfile[$j]"; $j++; # Put the rest of the comment in the box until($sdlfile[$j] =~ /^(;|:)/) # ':' is wrong, but used sometimes? { $sdlfile[$j] =~ s/'\n/\*\/\n/; print PROCFILE "$sdlfile[$j]"; $j++; } # Insert text box end instead of ';' print "$sdlfile[$j]"; print PROCFILE "/* CIF End Text */\n"; $j++; } # In a CIF label or Join statement, only the first (x,y) pair must be changed, # since the second (x,y) defines the size of the symbol. if($sdlfile[$j] =~ /\/\* CIF (Label|Join|Comment|Text) /i) { $sdlfile[$j]=~ s/\((\d+)/$1-$x/e; # Substitute '(x' with x minus offset $sdlfile[$j]=~ s/(\d+)\)/$1-$y/e; # Substitute 'y)' with y minus offset $sdlfile[$j]=~ s/(\d+),(\d+)/\($1,$2\)/; # Put the parantheses back in } elsif($sdlfile[$j] =~ /\/\* CIF/) { $sdlfile[$j]=~ s/\((\d+)/$1-$x/ge; # Substitute '(x' with x minus offset $sdlfile[$j]=~ s/(\d+)\)/$1-$y/ge; # Substitute 'y)' with y minus offset $sdlfile[$j]=~ s/(\d+),(\d+)/\($1,$2\)/g; # Put the parantheses back in } #Turn the nextStates into returns if($sdlfile[$j] =~ /\/\* CIF NextState \((\d+),(\d+)/i) { $x = $1+50; $y = $2; $sdlfile[$j] = "/* CIF Return($x,$y),(100,100) */\n"; $sdlfile[$j+1] = "return;\n"; } print PROCFILE "$sdlfile[$j]"; $j++; } #Print the last part of the procedure to the file. print PROCFILE "/* CIF End ProcedureDiagram */\n"; print PROCFILE "endprocedure $con;\n"; close(PROCFILE); #Insert reference to the procedure in the beginning of sdlfile $i=0; until($sdlfile[$i] =~ /^\/\* CIF CurrentPage/i) {$i++;} splice(@sdlfile,$i+1,0,"/* CIF Procedure (600,100) */\n"); splice(@sdlfile,$i+2,0,"/* CIF TextPosition (625,125) */\n"); splice(@sdlfile,$i+3,0,"procedure $con referenced;\n"); #Search through sdlfile and replace all joins to the connection with procedure calls $i = 0; while($i<@sdlfile) { if($sdlfile[$i] =~ /^join $con/i) { $sdlfile[$i-1] =~ /^\/\* CIF Join \((\d+),(\d+)\)/i; $x=$1-50; $y=$2; #print "Replacing an occurence of $sdlfile[$i]\n"; $sdlfile[$i-1] = "/* CIF ProcedureCall ($x,$y) */\n"; $sdlfile[$i] = "call $con;\n"; $x = $x+100; $y = $y+100; $y2 = $y+50; splice(@sdlfile,$i+1,0,"/* CIF Line ($x,$y),($x,$y2) */\n"); $x = $x-100; splice(@sdlfile,$i+2,0,"/* CIF NextState ($x,$y2) */\n"); splice(@sdlfile,$i+3,0,"nextstate $returnState;\n"); } #End replacing join $i++; } #End replacing all joins with calls #Deleting Connection definition print "Deleting definition of $con\n"; $prevline = ""; $i = 0; until($sdlfile[$i] =~ /^connection $con/i) {$i++}; #$i = $def-2; $i--; # Start with the Label CIF statement above the connection statement until($prevline =~ /^endconnection/i) { $prevline = $sdlfile[$i]; #print "$prevline"; splice(@sdlfile,$i,1); } } #End only one return } #End found definition } #End turn into procedure } # End Treating connections } sub stateOnNewPage { #Purpose: Insert pagebreaks before states and connection, see rule 'state and nextstate'(1) local($line) = ""; local($statename) = ""; local($notfound) = 1; local($pagedeclare) = 0; $lenght = @sdlfile; $i = 0; # Find the place in the CIF file header where the pages are declared while(($sdlfile[$i] =~ /(CIF ProcessDiagram)|(CIF Page)|(CIF Frame)/i)) {$i++; } $pagedeclare = $i-1; # Search trough sdlfile, looking for states and connections while($i< @sdlfile) { if( $sdlfile[$i] =~ /^(state|connection) (\w+|\*)/i) { $statename = "$1_$2"; if($statename eq "state_*") { print "Changed name on _*\n"; $statename = "asterisk_state"; } # print "checking $statename\n"; # Search backwards in sdlfile, to see if a pagebreak has been declared since # last endstate or endconnection $j = $i-1; $notfound = 1; while(!($sdlfile[$j] =~ /^(endstate|endconnection)/) && $notfound) { if($sdlfile[$j] =~ /^\/\* CIF CurrentPage/) { $notfound = 0; #print "$statename HAS a pagebreak\n"; } else {$j--; #print "."; } } if($notfound) # Insert code for pagebreak { splice(@sdlfile,$j+1,0,"/* CIF CurrentPage $statename */\n"); $i++; $lenght++; # Insert declaration of the new page in the CIF header splice(@sdlfile,$pagedeclare+1,0,"/* CIF Page $statename ($pageWidth,$pageHeight) */\n"); splice(@sdlfile,$pagedeclare+2,0,"/* CIF Frame (0,0),($pageWidth,$pageHeight) */\n"); $pagedeclare = $pagedeclare+2; $i=$i+2; #Skip two lines, since the declaration has moved everything downwards print "Inserted new page for $statename\n"; } # End insert pagebreak } # End backtracking $i++; } # End searching through sdlfile } sub alignPages { # Prupose: To make state symbols appear in the upper left corner local($pageStart) = 0; $i = 0; print "aligning pages\n"; # Search through sdlfile, check all pages while($i < @sdlfile) { if(($sdlfile[$i] =~ /\/\* CIF CurrentPage/i) && ($sdlfile[$i+1] =~ /\/\* CIF (State|Label)/i)) # Give up on the start page :-( # Page with state found { $i++; $sdlfile[$i] =~ /\/\* CIF (State|Label|Start) \((\d+),(\d+)\)/i; # Put the state symbol in the right place. # This might brake the lines to the symbol, this will be fixed by # resolvePageOverflow. Oops, there goes procedure independency... if($1 =~ /label/i) {$x = 350;} else {$x = 300;} if(($2 != $x) || ($3 != 100)) { $sdlfile[$i]=~ s/\((\d+)/$x/e; # Substitute '(x' with the right x $sdlfile[$i]=~ s/(\d+)\)/100/; # Substitute 'y)' with 100 $sdlfile[$i]=~ s/(\d+),(\d+)/\($1,$2\)/; # Put the parantheses back in } $pageStart = $i; $i++; #print "$sdlfile[$i]\n"; # Extract coordinates for the first symbol, evaluate offset until($sdlfile[$i] =~ /^\/\* CIF/i && ($sdlfile[$i] !~ /(Line|Comment)/i)) {$i++;} $sdlfile[$i] =~ /^\/\* CIF \w+ \((\d+),(\d+)\)/i; $x = $1-300; $y = $2-250; print "line: $i x: $x y: $y $sdlfile[$i]"; # Search through the page, alter all coordinates according to offset $i = $pageStart+1; # Jump back up to the line after state statement until($sdlfile[$i] =~ /^(endstate|endconnection)/i) { # In some CIF statements, only the first (x,y) pair must be changed, # since the second (x,y) defines the size of the symbol. if($sdlfile[$i] =~ /\/\* CIF (Label|Join|Comment|Text)/i) { $sdlfile[$i]=~ s/\((\d+)/$1-$x/e; # Substitute '(x' with x minus offset $sdlfile[$i]=~ s/(\d+)\)/$1-$y/e; # Substitute 'y)' with y minus offset $sdlfile[$i]=~ s/(\d+),(\d+)/\($1,$2\)/; # Put the parantheses back in #print "Replaced only 1st x,y on line $i: $sdlfile[$i]"; } elsif($sdlfile[$i] =~ /\/\* CIF/) { $sdlfile[$i]=~ s/\((\d+)/$1-$x/ge; # Substitute '(x' with x minus offset $sdlfile[$i]=~ s/(\d+)\)/$1-$y/ge; # Substitute 'y)' with y minus offset $sdlfile[$i]=~ s/(\d+),(\d+)/\($1,$2\)/g; # Put the parantheses back in } $i++; } # End aligning symbols # Adjust nextstates upwards if they are far below the previous symbol $i = $pageStart; until($sdlfile[$i] =~ /^(endstate|endconnection)/i) { if($sdlfile[$i] =~ /^\/\* CIF NextState/i) { #Search upwards to find the line to the nextstate $rightline = $i-1; until($sdlfile[$rightline] =~ /\/\* CIF Line/i) {$rightline--; } $sdlfile[$rightline] =~ /\/\* CIF Line \(\d+,(\d+)\),\(\d+,(\d+)\) \*\//; #Extract the two y-coordinates for the line #print "$sdlfile[$rightline]"; #print "y1: $1 y2: $2\n"; if($2-$1 != 50) { $newY = $1+50; $sdlfile[$rightline]=~ s/(\d+)\) \*\//$newY\) \*\//; #Adjust the second y-coordinate $sdlfile[$i]=~ s/(\d+)\) \*\//$newY\) \*\//; }#End moving misplaced nextstate } #End checking nextstate $i++; } #End checking page for misplaced nextstates } # End found page $i++; } # End searching through sdlfile } sub alignNextstates { #Purpose: Align nextstates on each page horizontally, see rule 'state and nextstate'(2) local(@statelines) = (); local($nextstates) = 0; local($largestY) = 0; local($line) = ""; local($currentState) = "start"; $i = 0; $lenght = @sdlfile; print "Aligning nextstates\n"; while($i < @sdlfile) { @statelines = (); $nextstates = 0; # For each page put the linenumbers of nextstate symbols in @statelines, until($sdlfile[$i] =~ /^(\/\* CIF CurrentPage|endprocess|endprocedure)/i) { if(($sdlfile[$i] =~ /^nextstate/) && ($currentState ne "start")) { # Don't move the nextstate in the start transition #print"$sdlfile[$i-1]"; #print"$sdlfile[$i]\n"; $statelines[$nextstates] = $i; $nextstates++; } # Keep track of wich state we're in if($sdlfile[$i] =~ /^state (.+);/i) {$currentState = $1; } $i++; } # Compare the y-coordinates and put the largest in $largestY $largestY = 0; foreach $line (@statelines) { #print "find Y: $sdlfile[$line-1]\n"; $sdlfile[$line-1] =~ /(\d+)\) \*\//; if($1 > $largestY) {$largestY = $1;} } # print "y: $largestY\n"; # Substitute the y-coordinate for the nextstate symbols and the line # to them with $largestY foreach $line (@statelines) { $sdlfile[$line-1] =~ s/(\d+)\) \*\/$/$largestY\) \*\//; #Search upwards to find the line to the nextstate $rightline = $line-2; until($sdlfile[$rightline] =~ /\/\* CIF Line/i) {$rightline--; } $sdlfile[$rightline] =~ s/(\d+)\) \*\/$/$largestY\) \*\//; #print"$sdlfile[$rightline]"; #print"$sdlfile[$line-1]\n"; } $i++; #Go past the pagebreak and into the next page } #end searching through sdlfile } sub makeSignalTextExtension { # Purpose: Put the parameters to a signal in a text extension if necessary, # see rule 'signal parameters' $i = 0; local($parameters) = 0; local($signalLine) = 0; local($CIFstring) = ""; local($extFound) = 0; local($signalname) = ""; print "Checking signals for necessary text extentions\n"; while($i < @sdlfile) { # If the signal has parameters, start checking it if($sdlfile[$i] =~ /^(output|input) (\w+)/i && !($sdlfile[$i] =~ /;/)) { $signalname = $2; $parameters = 0; $extFound = 0; $signalLine = $i; # Count the parameters, every line beginning with a letter, except 'comment' until(($sdlfile[$i] =~ /(;|^\/\* CIF Comment)/i) || ($extFound == 1)) { if($sdlfile[$i] =~ /^\(?\w+/ && !($sdlfile[$i] =~ /^comment/)) { $parameters++; } if($sdlfile[$i] =~ /CIF TextExtension/i) { $extFound = 1; print "$signalname HAS text extention\n"; } $i++; } if($parameters > 2 && ($extFound == 0)) { print "Added extension to signal $signalname\n"; # Extract the coordinates of the signal symbol $sdlfile[$signalLine-1] =~ /\/\* CIF .+put \((\d+),(\d+)\)/; $x = $1; $y = $2; # Insert CIF code for a text extension and line rigt after the signal statement $CIFstring = sprintf("/* CIF TextExtension (%d,%d) Right */\n",$x+250,$y); splice(@sdlfile,$signalLine+1,0,$CIFstring); $CIFstring = sprintf("/* CIF Line (%d,%d), (%d,%d) */\n",$x+250,$y+50,$x+200,$y+50); splice(@sdlfile,$signalLine+2,0,$CIFstring); # Insert CIF code to end the text extension right before the semicolon splice(@sdlfile,$i+2,0,"/* CIF End TextExtension */\n"); # $i+2, since two lines have been inserted $i=$i+3; } # End make text extension } # End check signal statement $i++; } # End search through sdlfile } sub removeInvisibleJoins { # Purpose: Expand all invisible joins, remove the invisble labels. # See rule 'connections' local($joinName) = ""; local($notFound) = 1; # Search trough sdlfile, expand all invisible joins print "Expanding invisible joins.\n"; $i = 0; while($i< @sdlfile) { if($sdlfile[$i] =~ /^\/\* CIF Join Invisible/i) { $sdlfile[$i+1] =~ /join (\w+);/i; $joinName = $1; #print "Found invisible join $joinName at line ",$i+1,".\n"; # Find the coordinates of the join if($sdlfile[$i-1] =~ /^\/\* CIF Line \((\d+),(\d+)/) {$joinLine = $i-1; $x = $1-100; $y =$2+50; print "x: $x y:$y $sdlfile[$joinLine]";} elsif($sdlfile[$i+2] =~ /^\/\* CIF Line \((\d+),(\d+)/) {$joinLine = $i+2; $x = $1-100; $y =$2+50; print "x: $x y:$y $sdlfile[$joinLine]"; } else {print "Couldn't find coordinates!\n"; } # Search for the definition of the connection $j= 0; $notFound = 1; while(($j < @sdlfile) && $notFound) { if(($sdlfile[$j] =~ /^$joinName/i) && ($sdlfile[$j-1] =~ /^\/\* CIF Label Invisible/i)) {$notFound = 0; print "Found $sdlfile[$j]";} else {$j++;} } # End finding definition #print "Definition at line $j: $sdlfile[$j]"; # Remove the join #print "deleting: $sdlfile[$i]"; splice(@sdlfile,$i,1); #print "deleting: $sdlfile[$i]"; splice(@sdlfile,$i,1); # Make the line to the expanded symbols $orgY = $y-50; $tmp = $x+100; $sdlfile[$joinLine] = "/* CIF Line ($tmp,$orgY),($tmp,$y) */\n"; # Find the coordinates of the first symbol after the invisible join, evaluate offset $sdlfile[$j+1] =~ /\((\d+),(\d+)\) \*\/$/; $x = $1 - $x; $y = $2 - $y; print "offset: $x, $y\n"; # Expand the connection $j++; print "Expanding $joinName:\n"; until($sdlfile[$j+1] =~ /^\/\* CIF Input/i || $sdlfile[$j-1] =~ /^(endstate|endconnection)/i) { splice(@sdlfile,$i,0,$sdlfile[$j]); if($j>$i) {$j++;} #Correct the coordiantes in the inserted line # In a CIF label or Join statement, only the first (x,y) pair must be changed, # since the second (x,y) defines the size of the symbol. if($sdlfile[$i] =~ /\/\* CIF (Label|Join|Comment|Text) /i) { $sdlfile[$i]=~ s/\((\d+)/$1-$x/e; # Substitute '(x' with x minus offset $sdlfile[$i]=~ s/(\d+)\)/$1-$y/e; # Substitute 'y)' with y minus offset $sdlfile[$i]=~ s/(\d+),(\d+)/\($1,$2\)/; # Put the parantheses back in } elsif($sdlfile[$i] =~ /\/\* CIF/) { $sdlfile[$i]=~ s/\((\d+)/$1-$x/ge; # Substitute '(x' with x minus offset $sdlfile[$i]=~ s/(\d+)\)/$1-$y/ge; # Substitute 'y)' with y minus offset $sdlfile[$i]=~ s/(\d+),(\d+)/\($1,$2\)/g; # Put the parantheses back in } #print "$sdlfile[$i]"; $i++; $j++; } # End expanding connection } # End found invisible join $i++; } # End expanding invisible joins #Search trough sdlfile, remove all invisible labels $i = 0; while($i< @sdlfile) { if ($sdlfile[$i] =~ /^\/\* CIF Label Invisible/i) { print "Removing label $sdlfile[$i+1]"; splice(@sdlfile,$i,1); splice(@sdlfile,$i,1); } $i++; } # End deleting labels } # End sub sub insertTextExtensions { # Purpose: Warn of missing TO/FROM statements/comments, insert dummy comments in the SDL, # see rule 'source and destination' $i = 0; local($found) = 0; local($commentString) = ""; local($signalname) = ""; local($direction) = ""; print "Checking TO/FROM-statements on signals\n"; while($i< @sdlfile) { $sdlfile[$i]; $i++; # If a signal statement is found, extract the signal name and coordinates if($sdlfile[$i] =~ /^\/\* CIF (in|out)put \((\d+),(\d+)\)/i) { $direction = $1; $x = $2; $y = $3; #print "dir: $direction\n"; $sdlfile[$i+1] =~ /put (\w+)/; $signalname = $1; $found = 0; # Check if the signal has a TO/FROM-statement or comment until(($sdlfile[$i] =~ /;$/) || $found) { $i++; if($sdlfile[$i] =~ /^(comment '(TO|FROM)|TO|VIA)/i) {$found = 1;} } # If the signal has no TO/FROM statement/comment, insert a comment if(!($found)) { if($sdlfile[$i] =~ /^$directionput/) # If the semicolon is on the same line as the signal name { $sdlfile[$i] =~ s/;//; $i++; splice(@sdlfile,$i,0,";\n"); # Put the semicolon on the next line } if($direction =~ /in/i) { $direction = "FROM";} else {$direction = "TO";} # Insert the CIF code for the comment symbol, a line and the text $commentString = sprintf("/* CIF Comment (%d,%d) Right */\n",$x+250,$y); splice(@sdlfile,$i,0,$commentString); $commentString = sprintf("/* CIF Line (%d,%d), (%d,%d) Dashed */\n",$x+250,$y,$x+200,$y); splice(@sdlfile,$i+1,0,$commentString); $commentString = "comment '$direction: ?'\n"; splice(@sdlfile,$i+2,0,$commentString); print "Warning: signal $signalname has no $direction-statement\n"; #print "Added dummy $direction-statement to $signalname\n"; } # End insert comment } # End searching through signal statement } # End searching through sdlfile } sub warnBranchOnDecision { # Purpose: Warn on decisions in the SDL, see rule 'control flow' $i = 0; local($currentState); while($i< @sdlfile) { $line = $sdlfile[$i]; $i++; # Keep track of wich state we're in if($line =~ /^state (.+);/i) {$currentState = $1; } if($line =~ /decision (.+);/i) { print "Warning: in state $currentState, the process branches on decision: $1\n"; } } } sub warnShortNames { # Purpose: Warn on short names in the SDL, see rule 'meaningful names' $i = 0; while($i< @sdlfile) { $line = $sdlfile[$i]; $i++; if($line =~ /(DCL|SIGNAL) (\w+)/i) { $name=$2; $len = length($2); if($len < 5) { if($1 eq "DCL") { print "Warning: variable $name has a short name\n";} if($1 eq "SIGNAL") { print "Warning: signal $name has a short name\n";} } } # End check declaration } # End search through sdlfile } sub resolvePageOverflow { # Purpose: Make sure there is enogh horizontal space on each page, if not # create new pages. local($stateName) = ""; local($pageName) = ""; local($rightX) = 0; local($newPages) = 0; local($flowsUsed) = 0; local($startTransition) = 0; local($spaceNeeded) = 0; local($isState) = 1; local($lastName) = ""; print "Checking horizontal spacing.\n"; $i = 0; while($i< @sdlfile) { if($sdlfile[$i] =~ /^\/\* CIF CurrentPage (\w+)/i) { $pageName = $1; $lastName = $pageName; until($sdlfile[$i] =~ /^\/\* CIF (State|Label)/i) {$i++;} if($sdlfile[$i] =~ /^\/\* CIF (State|Label) \((\d+),(\d+)/i) {if($1 eq "State"){$isState = 1; $statePosX = $2+100; $statePosY = $3+100;} if($1 eq "Label"){$isState = 0; $statePosX = $2; $statePosY = $3+100;} } if($sdlfile[$i+1] =~ /^(state|connection) (\w+)/i) {$stateName = $2;} $flowsUsed = 0; $newPages = 1; $i++; while($sdlfile[$i] !~ /^\/\* CIF CurrentPage/i && $i < @sdlfile) { if($sdlfile[$i] =~ /^(nextstate|join)/) { # Check that it's not the start transition $j = $i; $startTransition = 0; while(($sdlfile[$j] !~ /^(state|connection)/i) && !$startTransition) { if($sdlfile[$j] =~ /^start/i) {$startTransition = 1; #print "Is in start Transition?\n"; } $j--; } # End check for start transition if(!$startTransition) {$flowsUsed++;} } if($sdlfile[$i] =~ /^(input|save)/i) { $spaceNeeded = 0; if($sdlfile[$i-1] =~ /^\/\* CIF (Input|Save) \((\d+),(\d+)/) { $symbolX = $2; $symbolY = $3; print "$symbolX $symbolY $sdlfile[$i]"; if($1 =~ /save/i) {$spaceNeeded++;} } else {print "Couldn't find symbolX in line ",$i-1,": $sdlfile[$i-1]";} # Check space needed by the flowline $j = $i+1; while($sdlfile[$j] !~ /^(input|endstate|endconnection|save)/i) { if($sdlfile[$j] =~ /^(nextstate|join)/i) {$spaceNeeded++;} $j++; } print "Space: $spaceNeeded used: $flowsUsed\n"; if($spaceNeeded+$flowsUsed> $flowsPerPage) { # Create new page $newPages++; $flowsUsed = 0; print "Created new page $pageName\part$newPages\n"; if($isState) { splice(@sdlfile,$i-2,0,"/* CIF End State */\n"); $i++; splice(@sdlfile,$i-2,0,"endstate;\n"); $i++; splice(@sdlfile,$i-2,0,"/* CIF CurrentPage $pageName\part$newPages */\n"); $i++; splice(@sdlfile,$i-2,0,"/* CIF State (300,100) */\n"); $i++; splice(@sdlfile,$i-2,0,"state $stateName;\n"); $i++; } else { splice(@sdlfile,$i-2,0,"/* CIF End Label */\n"); $i++; splice(@sdlfile,$i-2,0,"endconnection;\n"); $i++; splice(@sdlfile,$i-2,0,"/* CIF CurrentPage $pageName\part$newPages */\n"); $i++; splice(@sdlfile,$i-2,0,"/* CIF Label (350,100) (100,100) */\n"); $i++; splice(@sdlfile,$i-2,0,"connection $stateName;\n"); $i++; } #$i++; $statePosX = 400; $statePosY = 200; # Find the place in the CIF file header where the pages are declared $pagedeclare = 0; while(($sdlfile[$pagedeclare] !~ /CIF Page $lastName/i)) {$pagedeclare++; } # Insert declaration of the new page in the CIF header splice(@sdlfile,$pagedeclare+2,0,"/* CIF Page $pageName\part$newPages ($pageWidth,$pageHeight) */\n"); splice(@sdlfile,$pagedeclare+3,0,"/* CIF Frame (0,0),($pageWidth,$pageHeight) */\n"); $pagedeclare = $pagedeclare+2; $i=$i+2; #Skip two lines, since the declaration has moved everything downwards $lastName = "$pageName\part$newPages"; } #Check horizontal alignment $rightX = $flowsUsed * $flowSpacing + 300; print "RightX: $rightX\n"; if($rightX != $symbolX) { # Move the flowline to the right x-coordinate #Check the line from the state symbol to the input symbol if($sdlfile[$i-2] =~ /CIF Line \((\d+),(\d+)/i) { unless($1 == $statePosX && $2 == statePosY) {$tmp = sprintf("/* CIF Line (%d,%d),(%d,%d),(%d,%d),(%d,%d) */\n",$statePosX,$statePosY,$statePosX,$statePosY+25,$rightX+100,$statePosY+25,$rightX+100,$symbolY); splice(@sdlfile,$i-2,1,$tmp); #print "$tmp"; } #print "$1 $2"; } else {print "Couldn't find line to symbol in $sdlfile[$i-2]";} # Evaluate offset $x = $symbolX- $rightX; print "Moving a flowline in $stateName $x pixels to the left\n"; print "at line $i : $sdlfile[$i]"; $i--; # Step one line up to start with the CIF signal $startDecide = $i; $flowsDecide = $flowsUsed; while($sdlfile[$i+1] !~ /^\/\* CIF (Input|Save)/i && $sdlfile[$i] !~ /^(endstate|endconnection)/i) { #Correct the x-coordiantes in the flowline # In a CIF label or Join statement, only the first x must be changed, # since the second x defines the size of the symbol. if($sdlfile[$i] =~ /\/\* CIF (Label|Join|Comment|Text) /i) { $sdlfile[$i]=~ s/\((\d+)/$1-$x/e; # Substitute '(x' with x minus offset $sdlfile[$i]=~ s/(\d+),(\d+)/\($1,$2/; # Put the parantheses back in } elsif($sdlfile[$i] =~ /\/\* CIF/) { $sdlfile[$i]=~ s/\((\d+)/$1-$x/ge; # Substitute '(x' with x minus offset $sdlfile[$i]=~ s/(\d+),(\d+)/\($1,$2/g; # Put the parantheses back in } if($sdlfile[$i] =~ /^(nextstate|join)/) {$flowsUsed++;} $i++; } # End adjusting x-coordinates } # End fix alignment } # End check input signal if($spaceNeeded > 1) { # Check spacing inside decisions $j = $startDecide; while($sdlfile[$j+1] !~ /^\/\* CIF (Input|Save)/i && ($sdlfile[$j+1] !~ /(endstate|endconnection)/i) && $j < @sdlfile) #|(endstate|endconnection))/i) { if($sdlfile[$j] =~ /^(join|nextstate)/i && ($sdlfile[$j+1] =~ /CIF Answer/i) && ($sdlfile[$j+2] =~ /\((\d+),(\d+)\) \*\//)) { $flowsDecide++; $x = $1 -100; print "Inside! x = $x, flows = $flowsDecide, $sdlfile[$j+2]"; #Check horizontal alignment $rightX = $flowsDecide * $flowSpacing + 300; print "RightX: $rightX\n"; if($x != $rightX) { # Evaluate offset $x = $x - $rightX; print "Moving a flowline Inside a decision in $stateName $x pixels to the left\n"; print "at line $j : $sdlfile[$j]"; while($sdlfile[$j+1] !~ /^(join|nextstate)/i) { #Correct the x-coordiantes in the flowline # In a CIF label or Join statement, only the first x must be changed, # since the second x defines the size of the symbol. if($sdlfile[$j] =~ /\/\* CIF (Label|Join|Comment|Text) /i) { $sdlfile[$j]=~ s/\((\d+)/$1-$x/e; # Substitute '(x' with x minus offset $sdlfile[$j]=~ s/(\d+),(\d+)/\($1,$2/; # Put the parantheses back in } elsif($sdlfile[$j] =~ /\/\* CIF/) { $sdlfile[$j]=~ s/\((\d+)/$1-$x/ge; # Substitute '(x' with x minus offset $sdlfile[$j]=~ s/(\d+),(\d+)/\($1,$2/g; # Put the parantheses back in } $j++; } # End adjusting x-coordinates } # End x != rightX } # End found a nextstate/join $j++; } # End searching the flowline } # End checking inside decisions $i++; } # End search through page } # End check page else {$i++;} } # End search through sdlfile } # End procedure sub removeEmptyPages { # Purpose: Remove pages that have become empty after deletion of connections $i = 0; while($i < @sdlfile) { if($sdlfile[$i+1] =~ /^\/\* CIF currentPage/i && $sdlfile[$i] =~ /^\/\* CIF currentPage (\w+)/i) { # Delete the pagebreak $pageName = $1; print "At line: $i Deleting pagebreak $pageName\n"; splice(@sdlfile,$i,1); } $i++; } # End removing unnecessary pagebreaks # Check if the declared pages are in fact used $i = 2; while($sdlfile[$i] =~ /^\/\* CIF (Frame|Page)/i) { if($sdlfile[$i] =~ /^\/\* CIF Page (\w+)/i) { $pageName = $1; #print "Checking page $pageName\n"; $inUse = 0; $j = $i; while(($j < @sdlfile) && ($inUse == 0)) { if($sdlfile[$j] =~ /^\/\* CIF currentPage $pageName/i) {$inUse = 1;} $j++; } # If not in use, Delete the declaration if($inUse == 0) { splice(@sdlfile,$i,1); splice(@sdlfile,$i,1); print "Deleted declaration of page $pageName\n"; } } # End chech declaration $i++; } # End removing unused declarations }