diff --git a/Changes b/Changes index 1b16de243..25bdbd7d6 100644 --- a/Changes +++ b/Changes @@ -11,6 +11,8 @@ indicates the contributor was also the author of the fix; Thanks! **** Removed coverage request variable; see Coverage limitations in docs. +**** Fix DOS carrage returns in multiline defines. [Ralf Karge] + * Verilator 3.602 09/11/2006 **** Fix function references under top inlined module. [David Hewson] diff --git a/src/V3PreLex.l b/src/V3PreLex.l index bfbed3c9e..bae1d7bc1 100644 --- a/src/V3PreLex.l +++ b/src/V3PreLex.l @@ -58,9 +58,9 @@ static void pslMoreNeeded(bool flag) { V3PreLex::s_currentLexp->m_pslMoreNeeded %x ARGMODE %x INCMODE -ws [ \t\r\f] -nl [\n] -cr [\m] +ws [ \t\f\r] +wsn [ \t\f] +crnl [\r]*[\n] quote [\"] backslash [\\] symb [a-zA-Z_][a-zA-Z0-9_$]* @@ -69,7 +69,7 @@ psl [p]sl /**************************************************************/ %% -^{ws}*"`line"{ws}+.*{nl} { V3PreLex::s_currentLexp->lineDirective(yytext); } +^{ws}*"`line"{ws}+.*{crnl} { V3PreLex::s_currentLexp->lineDirective(yytext); } /* Special directives we recognise */ "`include" { return(VP_INCLUDE); } @@ -96,7 +96,7 @@ psl [p]sl /* Pass-through strings */ {quote} { yy_push_state(STRMODE); yymore(); } <> { linenoInc(); yyerror("EOF in unterminated string"); yyleng=0; yyterminate(); } -{nl} { linenoInc(); yyerror("Unterminated string"); BEGIN(INITIAL); } +{crnl} { linenoInc(); yyerror("Unterminated string"); BEGIN(INITIAL); } [^\"\\] { yymore(); } {backslash}. { yymore(); } {quote} { yy_pop_state(); @@ -105,28 +105,26 @@ psl [p]sl /* Pass-through include <> filenames */ <> { linenoInc(); yyerror("EOF in unterminated include filename"); yyleng=0; yyterminate(); } -{nl} { linenoInc(); yyerror("Unterminated include filename"); BEGIN(INITIAL); } +{crnl} { linenoInc(); yyerror("Unterminated include filename"); BEGIN(INITIAL); } [^\>\\] { yymore(); } {backslash}. { yymore(); } [\>] { yy_pop_state(); return (VP_STRING); } /* Reading definition */ "/*" { yy_push_state(CMTMODE); yymore(); } -"//"[^\n]* { return (VP_COMMENT);} +"//"[^\n\r]* { return (VP_COMMENT);} <> { linenoInc(); yyerror("EOF (missing return?) in define value"); yyleng=0; yyterminate(); } -{nl} { linenoInc(); - yy_pop_state(); - return (VP_DEFVALUE); } /* Note contains a return */ -[^\/\*\n\m\\]+ | -[\\][^\n] | +{crnl} { linenoInc(); yy_pop_state(); yytext="\n"; yyleng=1; return (VP_DEFVALUE); } +[\\]{crnl} { linenoInc(); appendDefValue("\n",1); } /* Include return so can maintain output line count */ +[^\/\*\n\r\\]+ | +[\\][^\n\r] | . { appendDefValue(yytext,yyleng); } -[\\]{nl} { linenoInc(); appendDefValue("\n",1); } /* Define arguments */ "/*" { yy_push_state(CMTMODE); yymore(); } -"//"[^\n]* { return (VP_COMMENT);} +"//"[^\n\r]* { return (VP_COMMENT);} <> { yyerror("EOF in define argument list\n"); yyleng = 0; yyterminate(); } -{nl} { linenoInc(); yytext="\n"; yyleng=1; return(VP_WHITE); } +{crnl} { linenoInc(); yytext="\n"; yyleng=1; return(VP_WHITE); } {quote} { yy_push_state(STRMODE); yymore(); } [(] { V3PreLex::s_currentLexp->m_parenLevel++; appendDefValue(yytext,yyleng); } [,)] { if (V3PreLex::s_currentLexp->m_parenLevel>1) { @@ -135,26 +133,26 @@ psl [p]sl } else { unput(yytext[0]); yy_pop_state(); return (VP_DEFARG); }} -[^\/\*\n\m\\(,)\"]+ | +[^\/\*\n\r\\(,)\"]+ | . { appendDefValue(yytext,yyleng); } /* One line comments. */ "//"{ws}*{psl} { if (optPsl()) { pslMoreNeeded(true); yy_push_state(PSLONEM); return(VP_PSL); } else { yy_push_state(CMTONEM); yymore(); } } -"//"{nl} { linenoInc(); yytext="\n"; yyleng=1; return (VP_WHITE); } +"//"{ws}*{crnl} { linenoInc(); yytext="\n"; yyleng=1; return (VP_WHITE); } "//" { if (pslMoreNeeded()) { pslMoreNeeded(true); yy_push_state(PSLONEM); return(VP_PSL); } else { yy_push_state(CMTONEM); yymore(); } } -[^\n]* { yy_pop_state(); return (VP_COMMENT); } +[^\n\r]* { yy_pop_state(); return (VP_COMMENT); } /* Psl oneline comments */ [{(] { pslParenLevelInc(); return (VP_TEXT); } [})] { pslParenLevelDec(); return (VP_TEXT); } [;] { if (!pslParenLevel()) {BEGIN PSLONEE; pslMoreNeeded(false);} return (VP_TEXT); } <> { yyerror("EOF in '/* ... */' psl comment\n"); yyleng=0; yyterminate(); } -{nl} { linenoInc(); yy_pop_state(); return(VP_WHITE); } +{crnl} { linenoInc(); yy_pop_state(); yytext="\n"; yyleng=1; return(VP_WHITE); } /* Completed psl oneline comments */ -{nl} { linenoInc(); yy_pop_state(); return(VP_WHITE); } +{crnl} { linenoInc(); yy_pop_state(); yytext="\n"; yyleng=1; return(VP_WHITE); } {ws}+ { yymore(); } . { yyerror("Unexpected text following psl assertion\n"); } @@ -164,24 +162,25 @@ psl [p]sl {psl} { yyleng -= 3; BEGIN PSLMUL1; return (VP_COMMENT); } {ws}+ { yymore(); } "*/" { yy_pop_state(); return(VP_COMMENT); } -{nl} { linenoInc(); yymore(); } +{crnl} { linenoInc(); yymore(); } <> { yyerror("EOF in '/* ... */' block comment\n"); yyleng=0; yyterminate(); } . { BEGIN CMTMODE; yymore(); } /* Non 'psl' beginning in comment */ . { yymore(); } /* Psl C-style comments. */ -.|{nl} { yyless(0); BEGIN PSLMULM; return(VP_PSL); } +.|{crnl} { yyless(0); BEGIN PSLMULM; return(VP_PSL); } "*/" { yy_pop_state(); return(VP_COMMENT); } -"//"[^\n]* { return (VP_COMMENT); } /* Comments inside block comments get literal inclusion (later removal) */ +"//"[^\n\r]* { return (VP_COMMENT); } /* Comments inside block comments get literal inclusion (later removal) */ <> { yyerror("EOF in '/* ... */' psl comment\n"); yyleng=0; yyterminate(); } /* Define calls */ "`"{symb} { return (VP_DEFREF); } /* Generics */ -{nl} { linenoInc(); return(VP_WHITE); } +{crnl} { linenoInc(); yytext="\n"; yyleng=1; return(VP_WHITE); } {symb} { return (VP_SYMBOL); } -{ws}+ { return (VP_WHITE); } +[\r] { } +{wsn}+ { return (VP_WHITE); } . { return (VP_TEXT); } %% diff --git a/src/V3PreProc.cpp b/src/V3PreProc.cpp index 37cb2a461..face11d7b 100644 --- a/src/V3PreProc.cpp +++ b/src/V3PreProc.cpp @@ -537,10 +537,12 @@ int V3PreProcImp::getRawToken() { int tok = yylex(); if (debug()>4) { - char buf[10000]; strncpy(buf, yytext, yyleng); buf[yyleng] = '\0'; - for (char* cp=buf; *cp; cp++) if (*cp=='\n') *cp='$'; + string buf = string (yytext, yyleng); + string::size_type pos; + while ((pos=buf.find("\n")) != string::npos) { buf.replace(pos, 1, "\\n"); } + while ((pos=buf.find("\r")) != string::npos) { buf.replace(pos, 1, "\\r"); } fprintf (stderr, "%d: RAW %d %d: %-10s: %s\n", - fileline()->lineno(), m_off, m_state, tokenName(tok), buf); + fileline()->lineno(), m_off, m_state, tokenName(tok), buf.c_str()); } // On EOF, try to pop to upper level includes, as needed. @@ -867,12 +869,12 @@ string V3PreProcImp::getline() { while (NULL==(rtnp=strchr(m_lineChars.c_str(),'\n'))) { int tok = getToken(); if (debug()>4) { - char buf[100000]; - strncpy(buf, yytext, yyleng); - buf[yyleng] = '\0'; - for (char* cp=buf; *cp; cp++) if (*cp=='\n') *cp='$'; + string buf = string (yytext, yyleng); + string::size_type pos; + while ((pos=buf.find("\n")) != string::npos) { buf.replace(pos, 1, "\\n"); } + while ((pos=buf.find("\r")) != string::npos) { buf.replace(pos, 1, "\\r"); } fprintf (stderr,"%d: GETFETC: %-10s: %s\n", - fileline()->lineno(), tokenName(tok), buf); + fileline()->lineno(), tokenName(tok), buf.c_str()); } if (tok==VP_EOF) { // Add a final newline, in case the user forgot the final \n. diff --git a/test_regress/driver.pl b/test_regress/driver.pl index bf674aa7d..0f337ca6b 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -253,7 +253,7 @@ sub read { sub write_status { my $self = shift; my $filename = $self->{status_filename}; - my $fh = IO::File->new($filename,"w") or die "%Error: $! $filename,"; + my $fh = IO::File->new(">$filename") or die "%Error: $! $filename,"; print $fh Dumper($self); print $fh "1;"; $fh->close(); @@ -373,7 +373,7 @@ sub execute { my %param = (%{$self}, @_); # Default arguments are from $self $self->oprint("Run\n"); if ($param{vcs}) { - #my $fh = IO::File->new("simv.key","w") or die "%Error: $! simv.key,"; + #my $fh = IO::File->new(">simv.key") or die "%Error: $! simv.key,"; #$fh->print("quit\n"); $fh->close; $self->_run(logfile=>"obj_dir/".$self->{name}."_simv.log", cmd=>["./simv",], @@ -462,7 +462,7 @@ sub _run { sleep 1 if ($try!=7); my $moretry = $try!=0; - my $fh = IO::File->new($param{logfile},"r"); + my $fh = IO::File->new("<$param{logfile}"); next if !$fh && $moretry; local $/; undef $/; my $wholefile = <$fh>; @@ -508,7 +508,7 @@ sub _make_main { $self->_read_inputs(); my $filename = "obj_dir/$self->{VM_PREFIX}__main.cpp"; - my $fh = IO::File->new($filename,"w") or die "%Error: $! $filename,"; + my $fh = IO::File->new(">$filename") or die "%Error: $! $filename,"; my $VM_PREFIX = $self->{VM_PREFIX}; print $fh "#include \"$VM_PREFIX.h\"\n"; @@ -587,7 +587,7 @@ sub _make_top { $self->_read_inputs(); - my $fh = IO::File->new($self->{top_shell_filename},"w") or die "%Error: $! $self->{top_shell_filename},"; + my $fh = IO::File->new(">$self->{top_shell_filename}") or die "%Error: $! $self->{top_shell_filename},"; print $fh "module top;\n"; foreach my $inp (sort (keys %{$self->{inputs}})) { print $fh " reg ${inp};\n"; @@ -640,7 +640,7 @@ sub _read_inputs { my $self = shift; my $filename = $self->{top_filename}; $filename = "t/$filename" if !-r $filename; - my $fh = IO::File->new($filename) or die "%Error: $! $filename,"; + my $fh = IO::File->new("<$filename") or die "%Error: $! $filename,"; while (defined(my $line = $fh->getline)) { if ($line =~ /^\s*input\s*(\S+)\s*(\/[^\/]+\/|)\s*;/) { $self->{inputs}{$1} = $1; @@ -673,8 +673,8 @@ sub verilator_version { sub files_identical { my $fn1 = shift; my $fn2 = shift; - my $f1 = IO::File->new ($fn1) or die "%Error: $! $fn1,"; - my $f2 = IO::File->new ($fn2) or die "%Error: $! $fn2,"; + my $f1 = IO::File->new ("<$fn1") or die "%Error: $! $fn1,"; + my $f2 = IO::File->new ("<$fn2") or die "%Error: $! $fn2,"; my @l1 = $f1->getlines(); my @l2 = $f2->getlines(); my $nl = $#l1; $nl = $#l2 if ($#l2 > $nl); @@ -720,7 +720,7 @@ sub file_contents { my $filename = shift; if (!$_File_Contents_Cache{$filename}) { - my $fh = IO::File->new($filename,"r"); + my $fh = IO::File->new("<$filename"); if (!$fh) { $_File_Contents_Cache{$filename} = "_Already_Errored_"; $self->error("File_grep file not found: ".$filename."\n"); @@ -735,6 +735,15 @@ sub file_contents { return $_File_Contents_Cache{$filename}; } +sub write_wholefile { + my $self = (ref $_[0]? shift : $Last_Self); + my $filename = shift; + my $contents = shift; + my $fh = IO::File->new(">$filename") or die "%Error: $! writing $filename,"; + print $fh $contents; + $fh->close; +} + ####################################################################### ####################################################################### ####################################################################### diff --git a/test_regress/t/t_preproc.pl b/test_regress/t/t_preproc.pl index ffbc57e3d..f4c30d6ef 100755 --- a/test_regress/t/t_preproc.pl +++ b/test_regress/t/t_preproc.pl @@ -7,6 +7,7 @@ if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; } # redistribute it and/or modify it under the terms of either the GNU # General Public License or the Perl Artistic License. +$golden_out ||= "t/$Last_Self->{name}.out"; my $stdout_filename = "obj_dir/$Last_Self->{name}__test.vpp"; if (!$Last_Self->{v3}) { @@ -17,8 +18,8 @@ if (!$Last_Self->{v3}) { verilator_make_gcc=>0, stdout_filename => $stdout_filename, ); - ok(preproc_check("t/$Last_Self->{name}.v", $stdout_filename) - && files_identical($stdout_filename, "t/$Last_Self->{name}.out")); + ok(preproc_check($Last_Self->{top_filename}, $stdout_filename) + && files_identical($stdout_filename, $golden_out)); } sub preproc_check { diff --git a/test_regress/t/t_preproc_dos.pl b/test_regress/t/t_preproc_dos.pl new file mode 100755 index 000000000..743c02545 --- /dev/null +++ b/test_regress/t/t_preproc_dos.pl @@ -0,0 +1,30 @@ +#!/usr/bin/perl +if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; } +# $Id$ +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2006-2006 by Wilson Snyder. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# General Public License or the Perl Artistic License. + +top_filename("obj_dir/$Last_Self->{name}.v"); + +# Rather then having to maintain a new .v and .out, simply add returns +# to all lines of the existing t_preproc test. + +$golden_out ||= "obj_dir/$Last_Self->{name}.out"; + +{ + my $wholefile = file_contents("t/t_preproc.v"); + $wholefile =~ s/\n/\r\n/og; + write_wholefile("obj_dir/$Last_Self->{name}.v", $wholefile); +} +{ + my $wholefile = file_contents("t/t_preproc.out"); + $wholefile =~ s!t/t_preproc.v!obj_dir/t_preproc_dos.v!og; # Fix `line's + write_wholefile($golden_out, $wholefile); +} + +require 't/t_preproc.pl'; + +1;