/* -*- 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
<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; }
<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; }
//
-// 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
} 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.";
//
-// 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
"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))
//
-// 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
#define tREALTIME 521
#define tNVCPUSH 522
#define tNVCPOP 523
+#define tPLUSPLUS 524
+#define tMINUSMINUS 525
+#define tVAR 526
#endif // _SCAN_H
//
-// 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
// 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] = {
"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[] = {
//
-// 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
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;
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;
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)
{
}
}
+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
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());
}
}
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
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);
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();
}
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;
}
//
-// 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
}
}
+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)) {
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)));
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);
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