]> Nick Gasson's Git Repositories - nvc.git/commitdiff
Parse Verilog for loops master github/master sr.ht/master
authorNick Gasson <nick@nickg.me.uk>
Tue, 14 Jan 2025 20:45:55 +0000 (20:45 +0000)
committerNick Gasson <nick@nickg.me.uk>
Wed, 15 Jan 2025 21:52:14 +0000 (21:52 +0000)
src/lexer.l
src/nvc.c
src/scan.c
src/scan.h
src/vlog/vlog-node.c
src/vlog/vlog-node.h
src/vlog/vlog-parse.c
src/vlog/vlog-sem.c
test/test_vlog.c
test/vlog/parse1.v

index 6b17ac23222377dcd05913788ce128ddafd8fa95..3fd2e005f67f98b1bff7d31636088927dc0aba9c 100644 (file)
@@ -1,7 +1,7 @@
 /* -*- mode: c; c-basic-offset: 3 -*- */
 
 /*
- *  Copyright (C) 2011-2024  Nick Gasson
+ *  Copyright (C) 2011-2025  Nick Gasson
  *
  *  This program is free software: you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -662,6 +662,9 @@ BEFORE            ?i:before
 <VLOG>"(*"               { return tATTRBEGIN; }
 <VLOG>"*)"               { return tATTREND; }
 <VLOG>"%"                { return tPERCENT; }
+<VLOG>"++"               { return tPLUSPLUS; }
+<VLOG>"--"               { return tMINUSMINUS; }
+<VLOG>"var"              { return tVAR; }
 <VLOG>"specify"          { return tSPECIFY; }
 <VLOG>"endspecify"       { return tENDSPECIFY; }
 <VLOG>"primitive"        { return tPRIMITIVE; }
@@ -703,6 +706,7 @@ BEFORE            ?i:before
 <VLOG>"endfunction"      { return tENDFUNCTION; }
 <VLOG>"wait"             { return tWAIT; }
 <VLOG>"parameter"        { return tPARAMETER; }
+<VLOG>"for"              { return tFOR; }
 
 <VLOG>{SYSTASK}          { yylval.str = xstrdup(yytext); return tSYSTASK; }
 <VLOG>{VLOG_ID}          { yylval.str = xstrdup(yytext); return tID; }
index d26a527a71163132b382b3dd622a38ce45f75a4b..32a5f332ed61e2bae435208b930d6b8cdbefdf32 100644 (file)
--- a/src/nvc.c
+++ b/src/nvc.c
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2011-2024  Nick Gasson
+//  Copyright (C) 2011-2025  Nick Gasson
 //
 //  This program is free software: you can redistribute it and/or modify
 //  it under the terms of the GNU General Public License as published by
@@ -73,7 +73,7 @@ typedef struct {
 } cmd_state_t;
 
 const char copy_string[] =
-   "Copyright (C) 2011-2024  Nick Gasson\n"
+   "Copyright (C) 2011-2025  Nick Gasson\n"
    "This program comes with ABSOLUTELY NO WARRANTY. This is free software, "
    "and\nyou are welcome to redistribute it under certain conditions. See "
    "the GNU\nGeneral Public Licence for details.";
index 5561bec880339f82c29505536aba3b4b8a2aa398..de0f9ce62de881a187462c4475bc36effaf863a7 100644 (file)
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2014-2024  Nick Gasson
+//  Copyright (C) 2014-2025  Nick Gasson
 //
 //  This program is free software: you can redistribute it and/or modify
 //  it under the terms of the GNU General Public License as published by
@@ -262,7 +262,8 @@ const char *token_str(token_t tok)
          "before!", "before_", "before!_", "|->", "|=>", "next", "inf",
          "repeat", "do", "endpoint", "<<", ">>", "<<<", ">>>", "task",
          "endtask", "endfunction", "`begin_keywords", "`end_keywords", "real",
-         "shortreal", "realtime", "`__nvc_push", "`__nvc_pop",
+         "shortreal", "realtime", "`__nvc_push", "`__nvc_pop", "++", "--",
+         "var",
       };
 
       if (tok >= 200 && tok - 200 < ARRAY_LEN(token_strs))
index d7a24009b7cb5a86d7ea614fbcedc284c890a3c8..4bd27c071255f82fec6b60e99e3f8b7681ddb5b9 100644 (file)
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2022-2024  Nick Gasson
+//  Copyright (C) 2022-2025  Nick Gasson
 //
 //  This program is free software: you can redistribute it and/or modify
 //  it under the terms of the GNU General Public License as published by
@@ -424,5 +424,8 @@ bool is_scanned_as_psl(void);
 #define tREALTIME      521
 #define tNVCPUSH       522
 #define tNVCPOP        523
+#define tPLUSPLUS      524
+#define tMINUSMINUS    525
+#define tVAR           526
 
 #endif  // _SCAN_H
index 7650c1864a967c61e68c212b5e05b38165f0a3b5..75f815bac16eaf900f3c154a6e296eb665f4aaba 100644 (file)
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2022-2024  Nick Gasson
+//  Copyright (C) 2022-2025  Nick Gasson
 //
 //  This program is free software: you can redistribute it and/or modify
 //  it under the terms of the GNU General Public License as published by
@@ -174,6 +174,21 @@ static const imask_t has_map[V_LAST_NODE_KIND] = {
 
    // V_CONCAT
    (I_PARAMS),
+
+   // V_FOR_LOOP
+   (I_LEFT | I_VALUE | I_RIGHT | I_STMTS),
+
+   // V_FOR_INIT
+   (I_DECLS | I_STMTS),
+
+   // V_FOR_STEP
+   (I_STMTS),
+
+   // V_PREFIX
+   (I_TARGET | I_SUBKIND),
+
+   // V_POSTFIX
+   (I_TARGET | I_SUBKIND),
 };
 
 static const char *kind_text_map[V_LAST_NODE_KIND] = {
@@ -189,7 +204,8 @@ static const char *kind_text_map[V_LAST_NODE_KIND] = {
    "V_UNION_DECL", "V_STRUCT_DECL", "V_EVENT_CONTROL", "V_EMPTY",
    "V_REPEAT",     "V_WHILE",       "V_DO_WHILE",      "V_TASK_DECL",
    "V_FUNC_DECL",  "V_WAIT",        "V_PARAM_DECL",    "V_COND_EXPR",
-   "V_REAL",       "V_CONCAT",
+   "V_REAL",       "V_CONCAT",      "V_FOR_LOOP",      "V_FOR_INIT",
+   "V_FOR_STEP",   "V_PREFIX",      "V_POSTFIX",
 };
 
 static const change_allowed_t change_allowed[] = {
index f65d1a066e4bc72a1620dd152cf2310b286addc9..7c5d75187adea1ad1b23dddb3e44d1632914c53f 100644 (file)
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2022-2024  Nick Gasson
+//  Copyright (C) 2022-2025  Nick Gasson
 //
 //  This program is free software: you can redistribute it and/or modify
 //  it under the terms of the GNU General Public License as published by
@@ -94,6 +94,11 @@ typedef enum {
    V_COND_EXPR,
    V_REAL,
    V_CONCAT,
+   V_FOR_LOOP,
+   V_FOR_INIT,
+   V_FOR_STEP,
+   V_PREFIX,
+   V_POSTFIX,
 
    V_LAST_NODE_KIND
 } vlog_kind_t;
@@ -149,6 +154,11 @@ typedef enum {
    V_UNARY_IDENTITY,
 } vlog_unary_t;
 
+typedef enum {
+   V_INCDEC_PLUS,
+   V_INCDEC_MINUS,
+} vlog_incdec_t;
+
 typedef enum {
    V_ASSIGN_EQUALS,
 } vlog_assign_t;
index da33e4d0df333d5223ab58deb445763f019fa7dc..76315ef03bc848b039905d6d739b6c97bccd52e7 100644 (file)
@@ -102,6 +102,7 @@ static vlog_node_t p_constant_expression(void);
 static vlog_node_t p_data_type(void);
 static void p_list_of_variable_decl_assignments(vlog_node_t parent,
                                                 vlog_node_t datatype);
+static vlog_node_t p_variable_lvalue(void);
 
 static inline void _pop_state(const rule_state_t *r)
 {
@@ -1267,6 +1268,34 @@ static vlog_unary_t p_unary_operator(void)
    }
 }
 
+static vlog_incdec_t p_inc_or_dec_operator(void)
+{
+   // ++ | --
+
+   BEGIN("inc or dec operator");
+
+   switch (one_of(tPLUSPLUS, tMINUSMINUS)) {
+   case tMINUSMINUS: return V_INCDEC_MINUS;
+   case tPLUSPLUS:
+   default: return V_INCDEC_PLUS;
+   }
+}
+
+static vlog_node_t p_inc_or_dec_expression(vlog_node_t head)
+{
+   // inc_or_dec_operator { attribute_instance } variable_lvalue
+   //   | variable_lvalue { attribute_instance } inc_or_dec_operator
+
+   BEGIN_WITH_HEAD("inc or dec expression", head);
+
+   vlog_node_t v = vlog_new(head ? V_POSTFIX : V_PREFIX);
+   vlog_set_subkind(v, p_inc_or_dec_operator());
+   vlog_set_target(v, head ?: p_variable_lvalue());
+
+   vlog_set_loc(v, CURRENT_LOC);
+   return v;
+}
+
 static vlog_node_t p_nonbinary_expression(void)
 {
    // primary | unary_operator { attribute_instance } primary
@@ -1293,9 +1322,12 @@ static vlog_node_t p_nonbinary_expression(void)
          vlog_set_loc(v, CURRENT_LOC);
          return v;
       }
+   case tPLUSPLUS:
+   case tMINUSMINUS:
+      return p_inc_or_dec_expression(NULL);
    default:
       one_of(tID, tSTRING, tNUMBER, tUNSIGNED, tREAL, tSYSTASK, tLPAREN,
-             tLBRACE, tMINUS, tTILDE, tBANG);
+             tLBRACE, tMINUS, tTILDE, tBANG, tPLUSPLUS, tMINUSMINUS);
       return p_select(error_marker());
    }
 }
@@ -1723,6 +1755,116 @@ static vlog_node_t p_conditional_statement(void)
    return v;
 }
 
+static vlog_node_t p_variable_assignment(vlog_kind_t kind)
+{
+   // variable_lvalue = expression
+
+   BEGIN("variable assignment");
+
+   vlog_node_t v = vlog_new(kind);
+   vlog_set_target(v, p_variable_lvalue());
+
+   consume(tEQ);
+
+   vlog_set_value(v, p_expression());
+
+   vlog_set_loc(v, CURRENT_LOC);
+   return v;
+}
+
+static void p_list_of_variable_assignments(vlog_node_t parent)
+{
+   // variable_assignment { , variable_assignment }
+
+   BEGIN("list of variable assignments");
+
+   do {
+      vlog_node_t v = p_variable_assignment(V_BASSIGN);
+      vlog_add_stmt(parent, v);
+   } while (optional(tCOMMA));
+}
+
+static void p_for_variable_declaration(vlog_node_t parent)
+{
+   // [ var ] data_type variable_identifier = expression
+   //   { , variable_identifier = expression }
+
+   BEGIN("for variable declaration");
+
+   optional(tVAR);
+
+   vlog_node_t dt = p_data_type();
+
+   do {
+      vlog_node_t v = vlog_new(V_VAR_DECL);
+      vlog_set_ident(v, p_identifier());
+      vlog_set_type(v, dt);
+
+      consume(tEQ);
+
+      vlog_set_value(v, p_expression());
+
+      vlog_set_loc(v, CURRENT_LOC);
+      vlog_add_decl(parent, v);
+   } while (optional(tCOMMA));
+}
+
+static vlog_node_t p_for_initialization(void)
+{
+   // list_of_variable_assignments
+   //   | for_variable_declaration { , for_variable_declaration }
+
+   BEGIN("for initialization");
+
+   vlog_node_t v = vlog_new(V_FOR_INIT);
+
+   if (scan(tREG, tSTRUCT, tUNION, tENUM, tSVINT, tINTEGER, tSVREAL,
+            tSHORTREAL, tREALTIME, tLOGIC, tVAR)) {
+      do {
+         p_for_variable_declaration(v);
+      } while (optional(tCOMMA));
+   }
+   else
+      p_list_of_variable_assignments(v);
+
+   vlog_set_loc(v, CURRENT_LOC);
+   return v;
+}
+
+static vlog_node_t p_for_step(void)
+{
+   // operator_assignment | inc_or_dec_expression | function_subroutine_call
+
+   BEGIN("for step");
+
+   vlog_node_t v = vlog_new(V_FOR_STEP);
+
+   switch (peek()) {
+   case tPLUSPLUS:
+   case tMINUSMINUS:
+      vlog_add_stmt(v, p_inc_or_dec_expression(NULL));
+      break;
+   default:
+      {
+         vlog_node_t head = p_variable_lvalue();
+
+         switch (peek()) {
+         case tPLUSPLUS:
+         case tMINUSMINUS:
+            vlog_add_stmt(v, p_inc_or_dec_expression(head));
+            break;
+         default:
+            vlog_add_stmt(v, p_operator_assignment(head));
+            break;
+         }
+      }
+      break;
+   }
+
+   vlog_set_loc(v, CURRENT_LOC);
+   return v;
+}
+
 static vlog_node_t p_loop_statement(void)
 {
    // forever statement_or_null
@@ -1736,7 +1878,7 @@ static vlog_node_t p_loop_statement(void)
 
    BEGIN("loop statement");
 
-   switch (one_of(tFOREVER, tWHILE, tREPEAT, tDO)) {
+   switch (one_of(tFOREVER, tWHILE, tREPEAT, tDO, tFOR)) {
    case tFOREVER:
       {
          vlog_node_t v = vlog_new(V_FOREVER);
@@ -1800,6 +1942,39 @@ static vlog_node_t p_loop_statement(void)
          return v;
       }
 
+   case tFOR:
+      {
+         vlog_node_t v = vlog_new(V_FOR_LOOP);
+
+         consume(tLPAREN);
+
+         if (not_at_token(tSEMI))
+            vlog_set_left(v, p_for_initialization());
+         else
+            vlog_set_left(v, vlog_new(V_FOR_INIT));
+
+         consume(tSEMI);
+
+         if (not_at_token(tSEMI))
+            vlog_set_value(v, p_expression());
+
+         consume(tSEMI);
+
+         if (not_at_token(tRPAREN))
+            vlog_set_right(v, p_for_step());
+         else
+            vlog_set_right(v, vlog_new(V_FOR_STEP));
+
+         consume(tRPAREN);
+
+         vlog_node_t s = p_statement_or_null();
+         if (s != NULL)
+            vlog_add_stmt(v, s);
+
+         vlog_set_loc(v, CURRENT_LOC);
+         return v;
+      }
+
    default:
       should_not_reach_here();
    }
@@ -1872,12 +2047,13 @@ static vlog_node_t p_statement_item(void)
    case tWHILE:
    case tREPEAT:
    case tDO:
+   case tFOR:
       return p_loop_statement();
    case tWAIT:
       return p_wait_statement();
    default:
       one_of(tID, tAT, tHASH, tBEGIN, tSYSTASK, tIF, tFOREVER, tWHILE, tREPEAT,
-             tDO, tWAIT);
+             tDO, tFOR, tWAIT);
       drop_tokens_until(tSEMI);
       return NULL;
    }
index 28513c6451959c47872249c46d850ff8d4606468..431ce4829dba46df12e2a76cf68ada8d109840f0 100644 (file)
@@ -1,5 +1,5 @@
 //
-//  Copyright (C) 2022-2024  Nick Gasson
+//  Copyright (C) 2022-2025  Nick Gasson
 //
 //  This program is free software: you can redistribute it and/or modify
 //  it under the terms of the GNU General Public License as published by
@@ -650,6 +650,34 @@ static void vlog_check_concat(vlog_node_t expr)
    }
 }
 
+static void vlog_check_for_loop(vlog_node_t v)
+{
+   vlog_check(vlog_left(v));
+   vlog_check(vlog_right(v));
+
+   const int nstmts = vlog_stmts(v);
+   for (int i = 0; i < nstmts; i++)
+      vlog_check(vlog_stmt(v, i));
+}
+
+static void vlog_check_for_init(vlog_node_t v)
+{
+   const int ndecls = vlog_decls(v);
+   for (int i = 0; i < ndecls; i++)
+      vlog_check(vlog_decl(v, i));
+
+   const int nstmts = vlog_stmts(v);
+   for (int i = 0; i < nstmts; i++)
+      vlog_check(vlog_stmt(v, i));
+}
+
+static void vlog_check_for_step(vlog_node_t v)
+{
+   const int nstmts = vlog_stmts(v);
+   for (int i = 0; i < nstmts; i++)
+      vlog_check(vlog_stmt(v, i));
+}
+
 void vlog_check(vlog_node_t v)
 {
    switch (vlog_kind(v)) {
@@ -769,6 +797,15 @@ void vlog_check(vlog_node_t v)
    case V_CONCAT:
       vlog_check_concat(v);
       break;
+   case V_FOR_LOOP:
+      vlog_check_for_loop(v);
+      break;
+   case V_FOR_INIT:
+      vlog_check_for_init(v);
+      break;
+   case V_FOR_STEP:
+      vlog_check_for_step(v);
+      break;
    default:
       fatal_at(vlog_loc(v), "cannot check verilog node %s",
                vlog_kind_str(vlog_kind(v)));
index 46ee355ced0dbfb7e3795e52ee5effa816c75fd5..3bd0a3ece8448b8d88c6b4f87faedd28c63626e2 100644 (file)
@@ -169,7 +169,7 @@ START_TEST(test_parse1)
    vlog_node_t m = vlog_parse();
    fail_if(m == NULL);
    fail_unless(vlog_kind(m) == V_MODULE);
-   fail_unless(vlog_stmts(m) == 14);
+   fail_unless(vlog_stmts(m) == 15);
    fail_unless(vlog_ports(m) == 0);
    fail_unless(vlog_decls(m) == 14);
 
index d021554452e82850891bea72de1982701e247c36..e1a943d33f37460194b2f0bb2b6a64935429b419 100644 (file)
@@ -56,4 +56,11 @@ module parse1;
   realtime  r5 = 1.0;
   assign r2 = {x, y};
   assign {r1, r2} = {x, y};
+  initial begin
+    for (r1 = 1; r1 < 5; r1++)
+      x = x + 1;
+    for (;;r2 = r2 * x);
+    for (int i = 0; i > 0; --i);
+    for (var reg x = 5;;);
+  end
 endmodule // parse1