cosmopolitan/third_party/ctags/verilog.c
2022-11-13 13:26:28 -08:00

344 lines
6.9 KiB
C

// clang-format off
/*
* $Id: verilog.c 753 2010-02-27 17:53:32Z elliotth $
*
* 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 "third_party/ctags/general.h" /* must always come first */
#include "libc/mem/alg.h"
#include "libc/str/str.h"
#include "libc/runtime/runtime.h"
#include "third_party/ctags/debug.h"
#include "third_party/ctags/get.h"
#include "third_party/ctags/keyword.h"
#include "third_party/ctags/parse.h"
#include "third_party/ctags/read.h"
#include "third_party/ctags/vstring.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', "constant", "constants (define, parameter, specparam)" },
{ TRUE, 'e', "event", "events" },
{ TRUE, 'f', "function", "functions" },
{ TRUE, 'm', "module", "modules" },
{ TRUE, 'n', "net", "net data types" },
{ TRUE, 'p', "port", "ports" },
{ TRUE, 'r', "register", "register data types" },
{ TRUE, 't', "task", "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 == '=')
{
c = skipWhite (vGetc ());
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: */