%{ # $Id: Verilog.yp,v 1.2 2000/05/02 05:15:44 earl Exp $ # Copyright 2000 Earl A. Killian. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as # published by the Free Software Foundation. # # 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; see the file COPYING. If not, write to # the Free Software Foundation, Inc., 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # $::debug = 0; use lib '/home/waidy/lib'; use strict; use FileHandle; use Struct qw( :name(Verilog::Module) $name @ports @body(get:setref) %decl $instantiated :isa :new(name:ports:body)); use Struct qw( :name(Verilog::Primitive) $name @ports @body(get:setref) %decl $instantiated :isa :new(name:ports:body)); # Decls use Struct qw( :name(Verilog::Decl) @namelist $eolcomment :isa :new(namelist:eolcomment)); use Struct qw( :name(Verilog::Decl::Range) :extends(Verilog::Decl) $range :isa :new(namelist:eolcomment:range)); use Struct qw( :name(Verilog::Decl::Input) :extends(Verilog::Decl::Range) :isa :new(namelist:eolcomment:range)); use Struct qw( :name(Verilog::Decl::Output) :extends(Verilog::Decl::Range) :isa :new(namelist:eolcomment:range)); use Struct qw( :name(Verilog::Decl::Inout) :extends(Verilog::Decl::Range) :isa :new(namelist:eolcomment:range)); use Struct qw( :name(Verilog::Decl::Wire) :extends(Verilog::Decl::Range) :isa :new(namelist:eolcomment:range)); use Struct qw( :name(Verilog::Decl::Reg) :extends(Verilog::Decl::Range) :isa :new(namelist:eolcomment:range)); use Struct qw( :name(Verilog::Decl::Integer) :extends(Verilog::Decl) :isa :new(namelist:eolcomment)); use Struct qw( :name(Verilog::Decl::Real) :extends(Verilog::Decl) :isa :new(namelist:eolcomment)); use Struct qw( :name(Verilog::Decl::Event) :extends(Verilog::Decl) :isa :new(namelist:eolcomment)); use Struct qw( :name(Verilog::Decl::Time) :extends(Verilog::Decl) :isa :new(namelist:eolcomment)); # Module Body use Struct qw( :name(Verilog::Body) $lineno :isa :new(lineno)); use Struct qw( :name(Verilog::Body::Instance) :extends(Verilog::Body) $module $name @paramlist(get) :isa :new(lineno:module:name:paramlist)); use Struct qw( :name(Verilog::Body::Assign) :extends(Verilog::Body) $lhs $rhs :isa :new(lineno:lhs:rhs)); use Struct qw( :name(Verilog::Body::Always) :extends(Verilog::Body) $item :isa :new(lineno:item)); use Struct qw( :name(Verilog::Body::Initial) :extends(Verilog::Body) $item :isa :new(lineno:item)); use Struct qw( :name(Verilog::Body::Task) :extends(Verilog::Body) $valuetype $name @decl @body :isa :new(lineno:valuetype:name:decl:body)); # Statements use Struct qw( :name(Verilog::Stmt) $lineno :isa :new(lineno)); use Struct qw( :name(Verilog::Stmt::Null) :extends(Verilog::Stmt) :isa :new(lineno)); use Struct qw( :name(Verilog::Stmt::Assign) :extends(Verilog::Stmt) $lhs $rhs :isa :new(lineno:lhs:rhs)); use Struct qw( :name(Verilog::Stmt::If) :extends(Verilog::Stmt) $condition $then $else :isa :new(lineno:condition:then:else)); use Struct qw( :name(Verilog::Stmt::While) :extends(Verilog::Stmt) $condition $then $else :isa :new(lineno:condition:then:else)); use Struct qw( :name(Verilog::Stmt::For) :extends(Verilog::Stmt) $initvar $initvalue $condition $stepvar $stepvalue $body :isa :new(lineno:initvar:initvalue:condition:stepvar:stepvalue:body)); use Struct qw( :name(Verilog::Stmt::Forever) :extends(Verilog::Stmt) $body :isa :new(lineno:body)); use Struct qw( :name(Verilog::Stmt::Repeat) :extends(Verilog::Stmt) $count $body :isa :new(lineno:count:body)); use Struct qw( :name(Verilog::Stmt::Event) :extends(Verilog::Stmt) $event $body :isa :new(lineno:event:body)); use Struct qw( :name(Verilog::Stmt::Delay) :extends(Verilog::Stmt) $delay $body :isa :new(lineno:delay:body)); use Struct qw( :name(Verilog::Stmt::Task) :extends(Verilog::Stmt) $task @exprlist :isa :new(lineno:task:exprlist)); # Expressions use Struct qw( :name(Verilog::Expr) $op @args :isa :new(op:args)); # _Lexer data structures use Struct qw( :name(Verilog::InputFile) $filename $handle $lineno(get:inc) @cline :new(filename:handle:lineno)); use Struct qw( :name(Verilog::Ifdef) $thistest $alltests $filename $lineno $type :new(thistest:alltests:filename:lineno:type)); sub adddecl { my ($yyd, $d) = @_; my $decl = $yyd->{CMODULE}->ref_decl; foreach my $id ($d->namelist) { push (@{ $decl->{$id->[0]} }, $d); } $d; } %} %left UNARY %left '*' '/' '%' %left '+' '-' %left '<<' '>>' %left '<' '<=' '>' '>=' %left '==' '!=' '===' '!==' %left '&' %left '^' '^~' '~^' %left '|' %left '&&' %left '||' %left '?' ':' %start program %expect 1 %% program : topitem { [ $_[1] ]; } | program topitem { push (@{ $_[1] }, $_[2]); $_[1]; } ; # things that can occur at the top-level: module and primitive definitions topitem : MODULE ID ports ';' { my $m = new Verilog::Module ($_[2], $_[3], undef); my $yyd = $_[0]->YYData; $yyd->{CMODULE} = $m; $yyd->{MODULES}->{$_[2]} = $m; undef; # value for $_[5] } moditlist ENDMODULE { my $yyd = $_[0]->YYData; my $m = $yyd->{CMODULE}; $m->setref_body ($_[6]); $yyd->{CMODULE} = undef; $m; } | PRIMITIVE ID ports ';' { my $m = new Verilog::Primitive ($_[2], $_[3], undef); my $yyd = $_[0]->YYData; $yyd->{CMODULE} = $m; $yyd->{MODULES}->{$_[2]} = $m; undef; } primdecllist priminit TABLE tablelist ENDTABLE ENDPRIMITIVE { my $yyd = $_[0]->YYData; my $m = $yyd->{CMODULE}; push (@{ $_[6] }, $_[7], $_[9]); $m->setref_body ($_[6]); $yyd->{CMODULE} = undef; $m; } ; # declarations inside primitives primdecllist: primdecl { [ [ $_[1] ] ]; } | primdecllist primdecl { push(@{ $_[1] }, [ $_[2] ]); $_[1]; } ; primdecl: inputdecl | outputdecl | regdecl ; priminit: #empty { [ ]; } | INITIAL ID '=' expr ';' { [ $_[2], $_[4] ]; } ; # primitive tables tablelist: tableitem { [ $_[1] ]; } | tablelist tableitem { push(@{ $_[1] }, $_[2]); $_[1]; } ; tableitem: inputlist ':' outputsym ';' { [ $_[1], $_[3] ]; } ; inputlist: inputsym { [ $_[1] ]; } | inputlist inputsym { push(@{ $_[1] }, $_[2]); $_[1]; } ; inputsym: CONST { $_[1]; } | ID { $_[1]; } | '?' { $_[1]; } ; outputsym: CONST { $_[1]; } | ID { $_[1]; } ; # port list on module and primitive definitions ports : #empty { []; } | '(' ')' { []; } | '(' idlist ')' { $_[2]; } ; idlist : ID { [ $_[1] ]; } | idlist ',' ID { push(@{ $_[1] }, $_[3]); $_[1]; } ; # module body moditlist: #empty { []; } | moditlist modit { push(@{ $_[1] }, ref($_[2]) eq 'ARRAY' ? @{$_[2]} : $_[2] ); $_[1]; } ; modit : inputdecl | outputdecl | inoutdecl | wiredecl | regdecl | integerdecl | realdecl | eventdecl | timedecl | TASK ID ';' taskdecllist stmtornull ENDTASK { new Verilog::Body::Task ($_[0]->YYData->{LINENO}, undef, $_[2], $_[4], $_[5]); } | FUNCTION rangeortype ID ';' taskdecllist stmtornull ENDFUNCTION { new Verilog::Body::Task ($_[0]->YYData->{LINENO}, $_[2], $_[3], $_[5], $_[6]); } | ASSIGN lhs '=' expr ';' { new Verilog::Body::Assign ($_[0]->YYData->{LINENO}, $_[2], $_[4]); } | INITIAL stmt { new Verilog::Body::Initial ($_[0]->YYData->{LINENO}, $_[2]); } | ALWAYS stmt { new Verilog::Body::Always ($_[0]->YYData->{LINENO}, $_[2]); } | id # module name { my $yyd = $_[0]->YYData; my $m = $_[1]; $yyd->{INSTANTIATED}->{$m} = 1; $yyd->{CINST} = $m; undef; } modinstlist ';' { $_[3]; } ; parameterdecl: PARAMETER paramdecllist ';' { my $yyd = $_[0]->YYData; adddecl ($yyd, new Verilog::Decl::Parameter ($_[2], $yyd->{EOLCOMMENT})); } ; inputdecl: INPUT range decllist ';' { my $yyd = $_[0]->YYData; adddecl ($yyd, new Verilog::Decl::Input ($_[3], $yyd->{EOLCOMMENT}, $_[2])); } ; outputdecl: OUTPUT range decllist ';' { my $yyd = $_[0]->YYData; adddecl ($yyd, new Verilog::Decl::Output ($_[3], $yyd->{EOLCOMMENT}, $_[2])); } ; inoutdecl: INOUT range decllist ';' { my $yyd = $_[0]->YYData; adddecl ($yyd, new Verilog::Decl::Inout ($_[3], $yyd->{EOLCOMMENT}, $_[2])); } ; regdecl : REG range memlist ';' { my $yyd = $_[0]->YYData; adddecl ($yyd, new Verilog::Decl::Reg ($_[3], $yyd->{EOLCOMMENT}, $_[2])); } ; wiredecl: WIRE range wirelist ';' { my $yyd = $_[0]->YYData; adddecl ($yyd, new Verilog::Decl::Wire ($_[3], $yyd->{EOLCOMMENT}, $_[2])); } ; integerdecl: INTEGER memlist ';' { my $yyd = $_[0]->YYData; adddecl ($yyd, new Verilog::Decl::Integer ($_[2], $yyd->{EOLCOMMENT})); } ; realdecl: REAL decllist ';' { my $yyd = $_[0]->YYData; adddecl ($yyd, new Verilog::Decl::Real ($_[2], $yyd->{EOLCOMMENT})); } ; eventdecl: EVENT decllist ';' { my $yyd = $_[0]->YYData; adddecl ($yyd, new Verilog::Decl::Event ($_[2], $yyd->{EOLCOMMENT})); } ; timedecl: TIME decllist ';' { my $yyd = $_[0]->YYData; adddecl ($yyd, new Verilog::Decl::Time ($_[2], $yyd->{EOLCOMMENT})); } ; # declarations inside task definitions taskdecllist: #empty { []; } | taskdecllist taskdecl { push (@{ $_[1] }, $_[2]); $_[1] } ; taskdecl: parameterdecl | inputdecl | outputdecl | inoutdecl | regdecl | integerdecl | realdecl ; # parameter declarations paramdecllist: paramdecl { [ $_[1] ]; } | paramdecllist ',' paramdecl { push(@{ $_[1] }, $_[3]); $_[1]; } ; paramdecl: ID '=' expr { [ $_[1], $_[3] ]; } ; range : #empty { [0, 0]; } | '[' expr ':' expr ']' { [ $_[2], $_[4] ]; } ; rangeortype: range | INTEGER | REAL ; # list of wire names with optional initialization wirelist: wireinit { [ $_[1] ]; } | wirelist ',' wireinit { push (@{ $_[1] }, $_[3]); $_[1]; } ; wireinit: ID { [ $_[1], undef ]; } | ID '=' expr { [ $_[1], $_[3] ]; } ; # list of names without initialization decllist: ID { [ [ $_[1] ] ]; } | decllist ',' ID { push(@{ $_[1] }, [ $_[3] ]); $_[1]; } ; # list of names with optional array size memlist : ID arraydecl { [ [ $_[1], $_[2] ] ]; } | memlist ',' ID arraydecl { push(@{ $_[1] }, [ $_[3], $_[4] ]); $_[1] ; } ; # memory specification on reg declarations arraydecl: #empty { [0, 0]; } | '[' expr ':' expr ']' { [ $_[2], $_[4] ]; } ; # list of instanstiations modinstlist: modinst { [ $_[1] ]; } | modinstlist ',' modinst { push(@{ $_[1] }, $_[3]); $_[1]; } ; # module instantiation list element modinst : ID '(' paramlist ')' { my $yyd = $_[0]->YYData; new Verilog::Body::Instance ($yyd->{LINENO}, $yyd->{CINST}, $_[1], $_[3]); } ; # behavorial constructs stmt : lhs '=' expr ';' { [ new Verilog::Stmt::Assign ($_[0]->YYData->{LINENO}, $_[1], undef, $_[3]) ]; } | lhs '=' delaycontrol expr ';' { [ new Verilog::Stmt::Assign ($_[0]->YYData->{LINENO}, $_[1], $_[3], $_[4]) ]; } | lhs '=' eventcontrol expr ';' { [ new Verilog::Stmt::Assign ($_[0]->YYData->{LINENO}, $_[1], $_[3], $_[4]) ]; } | IF '(' expr ')' stmtornull { [ new Verilog::Stmt::If ($_[0]->YYData->{LINENO}, $_[3], $_[5], []) ]; } | IF '(' expr ')' stmtornull ELSE stmtornull { [ new Verilog::Stmt::If ($_[0]->YYData->{LINENO}, $_[3], $_[5], $_[7]) ]; } | CASE '(' expr ')' caselist ENDCASE { [ new Verilog::Stmt::Case ($_[0]->YYData->{LINENO}, $_[3], $_[5], $_[7]) ]; } | WHILE '(' expr ')' stmt { [ new Verilog::Stmt::While ($_[0]->YYData->{LINENO}, $_[3], $_[5]) ]; } | REPEAT '(' expr ')' stmt { [ new Verilog::Stmt::Repeat ($_[0]->YYData->{LINENO}, $_[3], $_[5]) ]; } | FOREVER stmt { [ new Verilog::Stmt::Forever ($_[0]->YYData->{LINENO}, $_[2]) ]; } | FOR '(' lhs '=' expr ';' expr ';' lhs '=' expr ')' stmt { [ new Verilog::Stmt::For ($_[0]->YYData->{LINENO}, $_[3], $_[5], $_[7], $_[9], $_[11], $_[13]) ]; } | BEGIN stmtlist END { $_[2]; } | BEGIN ':' ID blockdecl stmtlist END { new Verilog::Stmt::Block ($_[0]->YYData->{LINENO}, $_[3], $_[4], $_[5]); } | FORK ':' ID blockdecl stmtlist JOIN { new Verilog::Stmt::Fork ($_[0]->YYData->{LINENO}, $_[3], $_[4], $_[5]); } | WAIT '(' expr ')' stmtornull { [ new Verilog::Stmt::Wait ($_[0]->YYData->{LINENO}, $_[3], $_[5]) ]; } | '->' ID ';' { [ new Verilog::Stmt::Wait ($_[0]->YYData->{LINENO}, $_[3], $_[5]) ]; } | eventcontrol stmtornull { [ new Verilog::Stmt::Event ($_[0]->YYData->{LINENO}, $_[1], $_[2]) ]; } | delaycontrol stmtornull { [ new Verilog::Stmt::Delay ($_[0]->YYData->{LINENO}, $_[1], $_[2]) ]; } | id ';' # task invocation { [ new Verilog::Stmt::Task ($_[0]->YYData->{LINENO}, $_[1], []) ]; } | id '(' exprlist ')' ';' # task invocation { [ new Verilog::Stmt::Task ($_[0]->YYData->{LINENO}, $_[1], $_[3]) ]; } ; stmtornull: ';' { []; } | stmt { $_[1]; } ; stmtlist: #empty { []; } | stmtlist stmt { push(@{ $_[1] }, @{ $_[2] }); $_[1]; } ; blockdecl: parameterdecl | integerdecl | realdecl | timedecl | eventdecl ; delaycontrol: '#' CONST { $_[2]; } | '#' id { $_[2]; } | '#' '(' expr ')' { $_[3]; } ; eventcontrol: '@' id { $_[1]; } | '@' '(' eventexprlist ')' { $_[3]; } ; eventexpr: expr { $_[1]; } | POSEDGE expr { new Verilog::Expr ('POSEDGE', $_[1]); } | NEGEDGE expr { new Verilog::Expr ('NEGEDGE', $_[1]); } ; eventexprlist: eventexpr { [ $_[1] ]; } | eventexprlist OR eventexpr { push(@{ $_[1] }, $_[3]); $_[1]; } ; lhs : lhsitem { $_[1]; } | '{' lhslist '}' { new Verilog::Expr ('CAT', $_[2]); } ; lhsitem : id { $_[1]; } | id '[' expr ']' { new Verilog::Expr ('SUB', $_[1], $_[3]); } | id '[' expr ':' expr ']' { new Verilog::Expr ('SUB', $_[1], $_[3], $_[5]); } ; lhslist : lhsitem { [ $_[1] ]; } | lhslist ',' lhsitem { push(@{ $_[1] }, $_[3]); $_[1]; } ; paramlist: namedlist { $_[1]; } | orderedlist { $_[1]; } ; namedlist: namedparam { [ $_[1] ]; } | namedlist ',' namedparam { push(@{ $_[1] }, $_[3]); $_[1]; } ; namedparam: '.' ID '(' expr ')' { [ $_[2], $_[4] ]; } ; orderedlist: expr { [ $_[1] ]; } | orderedlist ',' expr { push(@{ $_[1] }, [undef, $_[3]]); $_[1]; } ; expr : id { $_[1]; } | id '[' subscript ']' { new Verilog::Expr ('SUB', $_[1], $_[3]); } | CONST { $_[1]; } | STRING { $_[1]; } | '!' expr %prec UNARY { new Verilog::Expr ('!', $_[2]); } | '~' expr %prec UNARY { new Verilog::Expr ('~', $_[2]); } | '&' expr %prec UNARY { new Verilog::Expr ('r&', $_[2]); } | '~&' expr %prec UNARY { new Verilog::Expr ('r~&', $_[2]); } | '|' expr %prec UNARY { new Verilog::Expr ('r|', $_[2]); } | '~|' expr %prec UNARY { new Verilog::Expr ('r~|', $_[2]); } | '^' expr %prec UNARY { new Verilog::Expr ('r^', $_[2]); } | '~^' expr %prec UNARY { new Verilog::Expr ('r~^', $_[2]); } | '^~' expr %prec UNARY { new Verilog::Expr ('r~^', $_[2]); } | expr '*' expr { new Verilog::Expr ('*', $_[1], $_[3]); } | expr '/' expr { new Verilog::Expr ('/', $_[1], $_[3]); } | expr '%' expr { new Verilog::Expr ('%', $_[1], $_[3]); } | expr '+' expr { new Verilog::Expr ('+', $_[1], $_[3]); } | expr '-' expr { new Verilog::Expr ('-', $_[1], $_[3]); } | expr '<<' expr { new Verilog::Expr ('<<', $_[1], $_[3]); } | expr '>>' expr { new Verilog::Expr ('>>', $_[1], $_[3]); } | expr '<' expr { new Verilog::Expr ('<', $_[1], $_[3]); } | expr '<=' expr { new Verilog::Expr ('<=', $_[1], $_[3]); } | expr '>' expr { new Verilog::Expr ('>', $_[1], $_[3]); } | expr '>=' expr { new Verilog::Expr ('>=', $_[1], $_[3]); } | expr '==' expr { new Verilog::Expr ('==', $_[1], $_[3]); } | expr '!=' expr { new Verilog::Expr ('!=', $_[1], $_[3]); } | expr '===' expr { new Verilog::Expr ('===', $_[1], $_[3]); } | expr '!==' expr { new Verilog::Expr ('!==', $_[1], $_[3]); } | expr '&' expr { new Verilog::Expr ('&', $_[1], $_[3]); } | expr '^' expr { new Verilog::Expr ('^', $_[1], $_[3]); } | expr '^~' expr { new Verilog::Expr ('^~', $_[1], $_[3]); } | expr '~^' expr { new Verilog::Expr ('^~', $_[1], $_[3]); } | expr '|' expr { new Verilog::Expr ('|', $_[1], $_[3]); } | expr '&&' expr { new Verilog::Expr ('&&', $_[1], $_[3]); } | expr '||' expr { new Verilog::Expr ('||', $_[1], $_[3]); } | expr '?' expr ':' expr { new Verilog::Expr ('?', $_[1], $_[3], $_[5]); } | ID '(' exprlist ')' { new Verilog::Expr ('FCALL', $_[1], $_[3]); } | '(' expr ')' { $_[2]; } | '{' catlist '}' { new Verilog::Expr ('CAT', $_[2]); } | '{' CONST '{' catlist '}' '}' { new Verilog::Expr ('REP', $_[2], $_[4]); } ; # list of expressions exprlist: #empty { []; } | expr { [ $_[1] ]; } | exprlist ',' expr { push(@{ $_[1] }, $_[3]); $_[1]; } ; catlist: expr { [ $_[1] ]; } | catlist ',' expr { push(@{ $_[1] }, $_[3]); $_[1]; } ; subscript: expr { [ $_[1] ]; } | expr ':' expr { [ $_[1], $_[3] ]; } ; id : ID { $_[1]; } | id '.' ID { $_[1].'.'.$_[3]; } ; %% use vars qw(%keyword); %keyword = ( 'module' => 'MODULE', 'endmodule' => 'ENDMODULE', 'primitive' => 'PRIMITIVE', 'endprimitive' => 'ENDPRIMITIVE', 'table' => 'TABLE', 'endtable' => 'ENDTABLE', 'task' => 'TASK', 'endtask' => 'ENDTASK', 'function' => 'FUNCTION', 'endfunction' => 'ENDFUNCTION', 'begin' => 'BEGIN', 'end' => 'END', 'case' => 'CASE', 'casez' => 'CASEZ', 'casex' => 'CASEX', 'endcase' => 'ENDCASE', 'fork' => 'FORK', 'join' => 'JOIN', 'input' => 'INPUT', 'output' => 'OUTPUT', 'inout' => 'INOUT', 'wire' => 'WIRE', 'reg' => 'REG', 'integer' => 'INTEGER', 'real' => 'REAL', 'parameter' => 'PARAMETER', 'assign' => 'ASSIGN', 'initial' => 'INITIAL', 'forever' => 'FOREVER', 'while' => 'WHILE', 'repeat' => 'REPEAT', 'always' => 'ALWAYS', 'if' => 'IF', 'else' => 'ELSE', 'for' => 'FOR', 'wait' => 'WAIT', 'disable' => 'DISABLE', 'deassign' => 'DEASSIGN', 'time' => 'TIME', 'event' => 'EVENT', 'posedge' => 'POSEDGE', 'negedge' => 'NEGEDGE', 'or' => 'OR' ); sub _Lexer { my ($parser) = @_; my $yyd = $parser->YYData; my $fs = $yyd->{FILESTACK}; my $fi = $fs->[$#$fs]; my $cline = $fi->ref_cline; my $ifstack = $yyd->{IFSTACK}; my $ifdef = $ifstack->[$#$ifstack]; token: for (;;) { my $v; while (!defined($v = shift(@$cline))) { # ran out of tokens from last line so go get another batch $fi->inc_lineno (1); my $handle = $fi->handle; while (!defined($_ = <$handle>)) { # end of file $handle->close; pop(@$fs); return ('', undef) # tell yapp we're done if @$fs == 0; $fi = $fs->[$#$fs]; $handle = $fi->handle; $cline = $fi->ref_cline; next token if @$cline > 0; } # break the line we just read into tokens @$cline = m{ \G # start after last token [\ \t\r\f]* # skip whitespace (not newline) ( [a-z_\$][a-z_0-9\$]* # identifier | [0-9][0-9_]* (?: \' (?: b[0-1xz_]+ # decimal number or sized constant | o[0-7xz_]+ | d[0-9xz_]+ | h[0-9a-fxz_]+ ) )? | \' (?: b[0-1xz_]+ # unsized constant | o[0-7xz_]+ | d[0-9xz_]+ | h[0-9a-fxz_]+ ) | \" [^\"]* \" # string | \/\/ .*\n # // comment | \/\* .*? \*\/ # /* ... */ comment | \/[^\/\*] # / | \={1,3} # = == === | \!\={0,2} # ! != !== !=== | \<[\=\<]? # < <= << | \>[\=\>]? # > >= >> | \~[\&\^]? # ~ ~& ~^ | \&{1,2} # & && | \|{1,2} # | || | \^[\|\~]? # ^ ^| ^~ | ->? # - -> | \`\w+ # directive | \\\S+(?=\s) # escaped identifier | [^\/\=\!\<\>\~\&\^\-\|\"0-9a-z_ \t\r\f\\] # [ ] ( ) { } @ # : ; ' , . ? + * % \n ) }xgi; # process newline or eolcomment my $eol = pop(@$cline); die ("token error: '$_'") unless $eol eq "\n" || $eol =~ m{^//.*\n}; chomp($eol); $yyd->{EOLCOMMENT} = $eol; } # while # $v contains the next token $yyd->{LINENO} = $fi->lineno; # make line number easily accessible # in semantic actions if (substr($v, 0, 1) eq "`") { # macro token my $macros = $yyd->{MACROS}; if ($v eq "`ifdef") { my $name = shift(@$cline); die ("$::myname: illegal `define $name @$cline.\n") unless $name =~ /^\w+$/; my $def = $macros->{$name}; $ifdef = new Verilog::Ifdef(defined($def), defined($def) && $ifdef->alltests, $fi->filename, $fi->lineno, $v); push (@$ifstack, $ifdef); } elsif ($v eq "`else") { die ("$::myname: `else at toplevel.\n") if @$ifstack <= 1; $ifdef->set_thistest(! $ifdef->thistest); $ifdef->set_alltests($ifdef->thistest && $ifstack->[$#$ifstack-1]->alltests); $ifdef->set_filename ($fi->filename); $ifdef->set_lineno ($fi->lineno); $ifdef->set_type ($v); } elsif ($v eq "`endif") { die ("$::myname: `endif at toplevel.\n") if @$ifstack <= 1; pop(@$ifstack); $ifdef = $ifstack->[$#$ifstack]; } elsif (! $ifdef->alltests) { # ignore directives inside failing ifdef } elsif ($v eq "`define") { my $name = shift(@$cline); die ("$::myname: illegal `define $name @$cline.\n") unless $name =~ /^\w+$/; $macros->{$name} = [@$cline]; @$cline = (); } elsif ($v eq "`include") { my $filename = shift(@$cline); die ("$::myname: string expected after `include.\n") unless $filename =~ /^".*"$/; $filename = substr($filename, 1, length($filename)-2); my $fh = new FileHandle ($filename, '<'); die ("$::myname: $!, opening $filename.\n") unless $fh; $fi = new Verilog::InputFile($filename, $fh, 0); push (@$fs, $fi); $cline = $fi->ref_cline; } else { # not a directive; must be a substitution my $def = $macros->{substr($v, 1)}; die ("$::myname: undefined macro $v.\n") unless defined($def); unshift (@$cline, @$def); } } elsif (! $ifdef-> alltests) { # ignore tokens inside failing ifdef } elsif ($v =~ m{^[a-z_\$]}i) { print STDERR ('ID: ', $v, "\n") if $::debug; return ($keyword{$v} || 'ID', $v); } elsif ($v =~ m{^[0-9']}) { print STDERR ('CONST: ', $v, "\n") if $::debug; return ('CONST', $v); } elsif ($v =~ m{^/[\/\*]}) { $yyd->{COMMENT} = $v; next token; } elsif ($v =~ m{^\"}) { print STDERR ('STRING: ', $v, "\n") if $::debug; return ('STRING', substr($v, 1, length($v)-2)); } elsif ($v =~ m{^\\}) { print STDERR ('ID: ', $v, "\n") if $::debug; return ('ID', $v); } else { print STDERR ("'", $v, "'\n") if $::debug; return ($v, $v); } } # for } # _Lexer sub _Error { my ($self) = @_; my $yyd = $self->YYData; exists $yyd->{ERRMSG} and do { print $yyd->{ERRMSG}; delete $yyd->{ERRMSG}; return; }; my $filestack = $yyd->{FILESTACK}; my $inputfile = $filestack->[$#$filestack]; if (defined($inputfile)) { print STDERR ("Syntax error on line ", $inputfile->lineno, " of ", $inputfile->filename, ".\n"); print STDERR (" tokens remaining on line: ", join(' ', $inputfile->cline), "\n"); } else { print STDERR ("Syntax error at end of file.\n"); } } sub Parse { my ($self, $filename) = @_; my $vfh = new FileHandle ($filename, '<'); die ("$::myname: $!, opening $filename.\n") unless defined($vfh); my $yyd = $self->YYData; $yyd->{EOLCOMMENT} = ''; $yyd->{COMMENT} = ''; my $filestack = [new Verilog::InputFile($filename, $vfh, 0)]; $yyd->{FILESTACK} = $filestack; $yyd->{CMODULE} = undef; my $modules = {}; $yyd->{MODULES} = $modules; $yyd->{MACROS} = {}; my $instantiated = {}; $yyd->{INSTANTIATED} = $instantiated; my $ifstack = [ new Verilog::Ifdef(1, 1, '', 0, '') ]; $yyd->{IFSTACK} = $ifstack; $yyd->{LINENO} = 0; my $vt = $self->YYParse( yylex => \&_Lexer, yyerror => \&_Error ); while (@$ifstack > 1) { my $id = pop @$ifstack; print STDERR ("$::myname: no `endif for ".$id->type." on line ".$id->lineno."\n"); } while (my($mname, $m) = each %$modules) { $m->set_instantiated ($instantiated->{$mname}); } $vt; }