#!/usr/bin/perl use strict; use warnings; my $linenum = 0; # sub nextline(): reads lines from INFILE until it gets to one that is not a # comment or whitespace and returns the line. also strips leading whitespace # and updates $linenum sub nextline { my $line; if( eof( INFILE ) ) { print( STDERR "unexpected EOF\n" ); exit; } $line = ; $linenum++; while( $line =~ m/^\#/ || $line =~ m/^\s*$/ ) { $line = ; $linenum++; } $line =~ s/^\s*//; return $line; } my ( $filename, $line, $numchords, $numstates, $numheaders, $next ); my ( @chords, @chordnames, @tmp, @table, @headers ); my $file = $ARGV[0]; open( INFILE, $file ); open( OUTFILE, ">$file.in" ); chomp( $line = nextline() ); unless( $line =~ m/^headers/ ) { print( STDERR "line 1 should read \"headers\"\n" ); exit; } # headers in the input file are the same as the output, so just copy them over $line = nextline(); $numheaders = 0; while( !($line =~ m/^end/ ) ) { push( @headers, $line ); $numheaders++; $line = nextline(); } print( OUTFILE "$numheaders\n" ); foreach $next (@headers) { print( OUTFILE $next ); } chomp( $line = nextline() ); unless( $line =~ m/chords/ ) { print( STDERR "line $linenum should read \"chords\"\n" ); exit; } $line = nextline(); $numchords = 0; while( !($line =~ m/^end/ ) ) { push( @chords, $line ); @tmp = split( / /, $line ); push( @chordnames, $tmp[0] ); $numchords++; $line = nextline(); } # print number of chords print( OUTFILE "$numchords\n" ); # chord definition also has the same format, so just copy them over foreach $next (@chords) { print( OUTFILE $next ); } chomp( $line = nextline() ); unless( $line =~ s/states:// ) { print( STDERR "line $linenum should read \"states: \"\n" ); exit; } $line =~ s/\s*//; $numstates = $line; print( OUTFILE "$numstates\n" ); $numstates = $numstates * $numchords + 1; my ( $col, $nextcol, $chordname, $subscript, $prob, $index, $rowtitle, $row ); my @probs; $nextcol = -1; $next = nextline(); for( my $i = 0; !($next =~ m/^end/); ++$i ) { for( my $j = 0; $j < $numstates; ++$j ) { $probs[$j] = 0; } if( $next =~ m/^\#/ ) { $next = nextline(); } # Pick out the row title if( $next =~ s/^(.*):\s*// ) { $rowtitle = $1; if( $i == 0 ) { unless( $rowtitle =~ m/start/ ) { print( STDERR "expected \"start:\" at line $linenum\n" ); exit; } } else { unless( $rowtitle =~ m/^(\w*)\((\d*)\)$/ ) { print( STDERR "\"$rowtitle\" produces a syntax error on line $linenum\n"); exit; } $chordname = $1; $subscript = $2; for( my $k = 0; $k < @chordnames; ++$k ) { if( $chordname eq $chordnames[$k] ) { $index = $k; } } # This calculates the row that the row title refers to. $row = ($index + 1) + (($subscript-1) * $numchords); # if $row != $i, then at least one row is missing from the input file. # Any rows missing from the input file have a 100 percent chance of # stopping. while( $row != $i ) { $probs[0] = 100; print( OUTFILE "@probs" ); print( OUTFILE "\n" ); $i++; $probs[0] = 0; } } } else { print( STDERR "syntax error on line $linenum\n" ); exit; } if( $next =~ s/\[stop\s(\w*)\]\s*// ) { $probs[0] = $1; } # Go through all the chords, figure out what column they correspond to, and # fill in the appropiate entry in @prob while( $next =~ s/^\[(\w*)\((\d*)\)\s(\d*)\]\s*// ) { $chordname = $1; $subscript = $2; $prob = $3; for( my $k = 0; $k < @chordnames; ++$k ) { if( $chordname eq $chordnames[$k] ) { $index = $k; } } $col = ($index + 1) + (($subscript-1) * $numchords); $probs[$col] = $prob; } $tmp[0] = 0; foreach $prob (@probs) { $tmp[0] += $prob; } # Since a syntax error will cause the reg exp to fail in the above while loop, # failure to add up to 100 can either mean a user addition error, or a syntax # error if( $tmp[0] != 100 ) { print( STDERR "line $linenum does not add up to 100 or has a syntax error\n" ); exit; } print( OUTFILE "@probs" ); print( OUTFILE "\n" ); $next = nextline(); } system( "./chord -f $file.in" );