338 lines
6.6 KiB
C
338 lines
6.6 KiB
C
|
/*
|
||
|
* Copyright (c) 2003, Darren Hiebert
|
||
|
*
|
||
|
* This source code is released for free distribution under the terms of the
|
||
|
* GNU General Public License.
|
||
|
*
|
||
|
* This module contains functions for generating tags for the Verilog HDL
|
||
|
* (Hardware Description Language).
|
||
|
*
|
||
|
* Language definition documents:
|
||
|
* http://www.eg.bucknell.edu/~cs320/verilog/verilog-manual.html
|
||
|
* http://www.sutherland-hdl.com/on-line_ref_guide/vlog_ref_top.html
|
||
|
* http://www.verilog.com/VerilogBNF.html
|
||
|
* http://eesun.free.fr/DOC/VERILOG/verilog_manual1.html
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* INCLUDE FILES
|
||
|
*/
|
||
|
#include "general.h" /* must always come first */
|
||
|
|
||
|
#include <string.h>
|
||
|
#include <setjmp.h>
|
||
|
|
||
|
#include "keyword.h"
|
||
|
#include "parse.h"
|
||
|
#include "read.h"
|
||
|
#include "vstring.h"
|
||
|
#include "get.h"
|
||
|
|
||
|
/*
|
||
|
* DATA DECLARATIONS
|
||
|
*/
|
||
|
typedef enum eException { ExceptionNone, ExceptionEOF } exception_t;
|
||
|
|
||
|
typedef enum {
|
||
|
K_UNDEFINED = -1,
|
||
|
K_CONSTANT,
|
||
|
K_EVENT,
|
||
|
K_FUNCTION,
|
||
|
K_MODULE,
|
||
|
K_NET,
|
||
|
K_PORT,
|
||
|
K_REGISTER,
|
||
|
K_TASK
|
||
|
} verilogKind;
|
||
|
|
||
|
typedef struct {
|
||
|
const char *keyword;
|
||
|
verilogKind kind;
|
||
|
} keywordAssoc;
|
||
|
|
||
|
/*
|
||
|
* DATA DEFINITIONS
|
||
|
*/
|
||
|
static int Ungetc;
|
||
|
static int Lang_verilog;
|
||
|
static jmp_buf Exception;
|
||
|
|
||
|
static kindOption VerilogKinds [] = {
|
||
|
{ TRUE, 'c', "variable", "constants (define, parameter, specparam)" },
|
||
|
{ TRUE, 'e', "typedef", "events" },
|
||
|
{ TRUE, 'f', "function", "functions" },
|
||
|
{ TRUE, 'm', "class", "modules" },
|
||
|
{ TRUE, 'n', "variable", "net data types" },
|
||
|
{ TRUE, 'p', "variable", "ports" },
|
||
|
{ TRUE, 'r', "variable", "register data types" },
|
||
|
{ TRUE, 't', "function", "tasks" }
|
||
|
};
|
||
|
|
||
|
static keywordAssoc VerilogKeywordTable [] = {
|
||
|
{ "`define", K_CONSTANT },
|
||
|
{ "event", K_EVENT },
|
||
|
{ "function", K_FUNCTION },
|
||
|
{ "inout", K_PORT },
|
||
|
{ "input", K_PORT },
|
||
|
{ "integer", K_REGISTER },
|
||
|
{ "module", K_MODULE },
|
||
|
{ "output", K_PORT },
|
||
|
{ "parameter", K_CONSTANT },
|
||
|
{ "real", K_REGISTER },
|
||
|
{ "realtime", K_REGISTER },
|
||
|
{ "reg", K_REGISTER },
|
||
|
{ "specparam", K_CONSTANT },
|
||
|
{ "supply0", K_NET },
|
||
|
{ "supply1", K_NET },
|
||
|
{ "task", K_TASK },
|
||
|
{ "time", K_REGISTER },
|
||
|
{ "tri0", K_NET },
|
||
|
{ "tri1", K_NET },
|
||
|
{ "triand", K_NET },
|
||
|
{ "tri", K_NET },
|
||
|
{ "trior", K_NET },
|
||
|
{ "trireg", K_NET },
|
||
|
{ "wand", K_NET },
|
||
|
{ "wire", K_NET },
|
||
|
{ "wor", K_NET }
|
||
|
};
|
||
|
|
||
|
/*
|
||
|
* FUNCTION DEFINITIONS
|
||
|
*/
|
||
|
|
||
|
static void initialize (const langType language)
|
||
|
{
|
||
|
size_t i;
|
||
|
const size_t count =
|
||
|
sizeof (VerilogKeywordTable) / sizeof (VerilogKeywordTable [0]);
|
||
|
Lang_verilog = language;
|
||
|
for (i = 0 ; i < count ; ++i)
|
||
|
{
|
||
|
const keywordAssoc* const p = &VerilogKeywordTable [i];
|
||
|
addKeyword (p->keyword, language, (int) p->kind);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void vUngetc (int c)
|
||
|
{
|
||
|
Assert (Ungetc == '\0');
|
||
|
Ungetc = c;
|
||
|
}
|
||
|
|
||
|
static int vGetc (void)
|
||
|
{
|
||
|
int c;
|
||
|
if (Ungetc == '\0')
|
||
|
c = fileGetc ();
|
||
|
else
|
||
|
{
|
||
|
c = Ungetc;
|
||
|
Ungetc = '\0';
|
||
|
}
|
||
|
if (c == '/')
|
||
|
{
|
||
|
int c2 = fileGetc ();
|
||
|
if (c2 == EOF)
|
||
|
longjmp (Exception, (int) ExceptionEOF);
|
||
|
else if (c2 == '/') /* strip comment until end-of-line */
|
||
|
{
|
||
|
do
|
||
|
c = fileGetc ();
|
||
|
while (c != '\n' && c != EOF);
|
||
|
}
|
||
|
else if (c2 == '*') /* strip block comment */
|
||
|
{
|
||
|
c = skipOverCComment();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fileUngetc (c2);
|
||
|
}
|
||
|
}
|
||
|
else if (c == '"') /* strip string contents */
|
||
|
{
|
||
|
int c2;
|
||
|
do
|
||
|
c2 = fileGetc ();
|
||
|
while (c2 != '"' && c2 != EOF);
|
||
|
c = '@';
|
||
|
}
|
||
|
if (c == EOF)
|
||
|
longjmp (Exception, (int) ExceptionEOF);
|
||
|
return c;
|
||
|
}
|
||
|
|
||
|
static boolean isIdentifierCharacter (const int c)
|
||
|
{
|
||
|
return (boolean)(isalnum (c) || c == '_' || c == '`');
|
||
|
}
|
||
|
|
||
|
static int skipWhite (int c)
|
||
|
{
|
||
|
while (isspace (c))
|
||
|
c = vGetc ();
|
||
|
return c;
|
||
|
}
|
||
|
|
||
|
static int skipPastMatch (const char *const pair)
|
||
|
{
|
||
|
const int begin = pair [0], end = pair [1];
|
||
|
int matchLevel = 1;
|
||
|
int c;
|
||
|
do
|
||
|
{
|
||
|
c = vGetc ();
|
||
|
if (c == begin)
|
||
|
++matchLevel;
|
||
|
else if (c == end)
|
||
|
--matchLevel;
|
||
|
}
|
||
|
while (matchLevel > 0);
|
||
|
return vGetc ();
|
||
|
}
|
||
|
|
||
|
static boolean readIdentifier (vString *const name, int c)
|
||
|
{
|
||
|
vStringClear (name);
|
||
|
if (isIdentifierCharacter (c))
|
||
|
{
|
||
|
while (isIdentifierCharacter (c))
|
||
|
{
|
||
|
vStringPut (name, c);
|
||
|
c = vGetc ();
|
||
|
}
|
||
|
vUngetc (c);
|
||
|
vStringTerminate (name);
|
||
|
}
|
||
|
return (boolean)(name->length > 0);
|
||
|
}
|
||
|
|
||
|
static void tagNameList (const verilogKind kind, int c)
|
||
|
{
|
||
|
vString *name = vStringNew ();
|
||
|
boolean repeat;
|
||
|
Assert (isIdentifierCharacter (c));
|
||
|
do
|
||
|
{
|
||
|
repeat = FALSE;
|
||
|
if (isIdentifierCharacter (c))
|
||
|
{
|
||
|
readIdentifier (name, c);
|
||
|
makeSimpleTag (name, VerilogKinds, kind);
|
||
|
}
|
||
|
else
|
||
|
break;
|
||
|
c = skipWhite (vGetc ());
|
||
|
if (c == '[')
|
||
|
c = skipPastMatch ("[]");
|
||
|
c = skipWhite (c);
|
||
|
if (c == '=')
|
||
|
{
|
||
|
if (c == '{')
|
||
|
skipPastMatch ("{}");
|
||
|
else
|
||
|
{
|
||
|
do
|
||
|
c = vGetc ();
|
||
|
while (c != ',' && c != ';');
|
||
|
}
|
||
|
}
|
||
|
if (c == ',')
|
||
|
{
|
||
|
c = skipWhite (vGetc ());
|
||
|
repeat = TRUE;
|
||
|
}
|
||
|
else
|
||
|
repeat = FALSE;
|
||
|
} while (repeat);
|
||
|
vStringDelete (name);
|
||
|
vUngetc (c);
|
||
|
}
|
||
|
|
||
|
static void findTag (vString *const name)
|
||
|
{
|
||
|
const verilogKind kind = (verilogKind) lookupKeyword (vStringValue (name), Lang_verilog);
|
||
|
if (kind == K_CONSTANT && vStringItem (name, 0) == '`')
|
||
|
{
|
||
|
/* Bug #961001: Verilog compiler directives are line-based. */
|
||
|
int c = skipWhite (vGetc ());
|
||
|
readIdentifier (name, c);
|
||
|
makeSimpleTag (name, VerilogKinds, kind);
|
||
|
/* Skip the rest of the line. */
|
||
|
do {
|
||
|
c = vGetc();
|
||
|
} while (c != '\n');
|
||
|
vUngetc (c);
|
||
|
}
|
||
|
else if (kind != K_UNDEFINED)
|
||
|
{
|
||
|
int c = skipWhite (vGetc ());
|
||
|
|
||
|
/* Many keywords can have bit width.
|
||
|
* reg [3:0] net_name;
|
||
|
* inout [(`DBUSWIDTH-1):0] databus;
|
||
|
*/
|
||
|
if (c == '(')
|
||
|
c = skipPastMatch ("()");
|
||
|
c = skipWhite (c);
|
||
|
if (c == '[')
|
||
|
c = skipPastMatch ("[]");
|
||
|
c = skipWhite (c);
|
||
|
if (c == '#')
|
||
|
{
|
||
|
c = vGetc ();
|
||
|
if (c == '(')
|
||
|
c = skipPastMatch ("()");
|
||
|
}
|
||
|
c = skipWhite (c);
|
||
|
if (isIdentifierCharacter (c))
|
||
|
tagNameList (kind, c);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void findVerilogTags (void)
|
||
|
{
|
||
|
vString *const name = vStringNew ();
|
||
|
volatile boolean newStatement = TRUE;
|
||
|
volatile int c = '\0';
|
||
|
exception_t exception = (exception_t) setjmp (Exception);
|
||
|
|
||
|
if (exception == ExceptionNone) while (c != EOF)
|
||
|
{
|
||
|
c = vGetc ();
|
||
|
switch (c)
|
||
|
{
|
||
|
case ';':
|
||
|
case '\n':
|
||
|
newStatement = TRUE;
|
||
|
break;
|
||
|
|
||
|
case ' ':
|
||
|
case '\t':
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
if (newStatement && readIdentifier (name, c))
|
||
|
findTag (name);
|
||
|
newStatement = FALSE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
vStringDelete (name);
|
||
|
}
|
||
|
|
||
|
extern parserDefinition* VerilogParser (void)
|
||
|
{
|
||
|
static const char *const extensions [] = { "v", NULL };
|
||
|
parserDefinition* def = parserNew ("Verilog");
|
||
|
def->kinds = VerilogKinds;
|
||
|
def->kindCount = KIND_COUNT (VerilogKinds);
|
||
|
def->extensions = extensions;
|
||
|
def->parser = findVerilogTags;
|
||
|
def->initialize = initialize;
|
||
|
return def;
|
||
|
}
|
||
|
|
||
|
/* vi:set tabstop=4 shiftwidth=4: */
|