// 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: */