/** Verilog Mode -- Maybe missing some keywords as I don't have proper ** Verilog language definition documentation available, but it works ** alright for me! This file was "hacked" from the Vhdl.e file provided ** in Epsilon 12. Just like VHDL mode, the indenter could use some ** work. ** Author -- Tom Almy, tom@almy.us ** Date -- July 2003 ** Lugaru customers may use freely. **/ /************************************************** -*- tab-width:4 -*- * * "Epsilon" is a registered trademark licensed to Lugaru Software, Ltd. * * "EEL" and "Lugaru" are trademarks of Lugaru Software, Ltd. * * * * Copyright (C) 2003 Lugaru Software Ltd. All rights reserved. * * * * Limited permission is hereby granted to reproduce and modify this * * copyrighted material provided that the resulting code is used only in * * conjunction with Lugaru products and that this notice is retained in * * any such reproduction or modification. * ************************************************************************/ #include "eel.h" #include "proc.h" #include "colcode.h" char _verilog_mode_name[] = "Verilog"; keytable verilog_tab; /* key table for verilog mode */ user char compile_verilog_cmd[128] = "verilog \"%r\""; // execute this file user char verilog_indent = 4; user char auto_show_verilog_delimiters = 1; user char verilog_auto_show_delim_chars[20] = "{[()]}"; color_class vhdl_comment; color_class vhdl_string; color_class vhdl_keyword; color_class vhdl_identifier; color_verilog_range(from, to) // recolor just this section { // last colored region may go past to int t = -1, talk, s, talk_at = 0; if (from >= to) return to; save_var point, matchstart, matchend; if (from < to) set_character_color(from, to, -1); point = from; save_var case_fold = 1; talk = (to - from > 20000); // show status during long delays while (point < to) { if (!re_search(1, "[a-z_][a-z0-9_]*('[a-z0-9_]+)*" "|[0-9.][0-9.]*(e[-+]?[0-9]+|'[bohd][0-9a-fz]+)?|//|/<*>|[\"\\]")) { t = size(); break; } t = matchstart; switch (character(point - 1)) { // check last char case '/': // found one line comment nl_forward(); set_character_color(t, point, color_class vhdl_comment); break; case '*': // found /* starting comment search(1, "*/"); set_character_color(t, point, color_class vhdl_comment); break; case '"': // found a string literal point = t; re_search(1, "\"([^\"\\\n]|\\(.|\n))*[\"\n]"); set_character_color(t, point, color_class vhdl_string); if (get_character_color(point, (int *) 0, &s) == color_class vhdl_string && s > to) // fix up after if (point < (to = s)) set_character_color(point, to, -1); // quoted "'s break; case '\\': // \arbitrary name\ is an identifier. if (re_search(1, "[ \t\\\n]")) set_character_color(t, point, color_class vhdl_identifier); break; default: // found identifier, kywd, or number if ( character(t-1) == '`' ) { t = t - 1; } set_character_color(t, point, verilog_keyword_color(t)); break; } if (talk && point > talk_at + 2000) { note("Coloring VERILOG program: %d%% complete...", muldiv(point - from, 100, to - from)); talk_at = point; } } if (to < t) set_character_color(to, t, -1); if (talk) note(""); return point; } verilog_keyword_color(from) // return color for "identifier" from here to point { // (something with alpha or digits) char buf[500]; if (point - from > sizeof(buf) / sizeof(*buf) - 10) save_var point = from + sizeof(buf) / sizeof(*buf) - 10; buf[0] = '|'; // get identifier, between | chars grab(from, point, buf + 1); if (index("0123456789-", buf[1]) || buf[1] == '.' && isdigit(buf[2])) return c_number_color(buf + 1); strcpy(buf + point - from + 1, "|"); if (is_verilog_keyword(buf)) return color_class vhdl_keyword; return color_class vhdl_identifier; } is_verilog_keyword(p) // is text in p (must be surrounded by |'s) a keyword? char *p; { if (strstr("|module|task|parameter|input|output|inout|reg|wire|" "assign|always|posedge|negedge|if|else|begin|end|" "case|default|endmodule|endcase|endtask|for|while|do|" "`if|`else|`endif|`include|`timescale|`define|" "initial|forever|real|integer|defparam|", p)) return 1; return 0; } // The indenter just indents like the previous non-comment line for now. // Some rules it might use someday: // If the previous line has an open parenthesis, align under that. // If the previous line's last word is "loop", "is", "then", or "begin", // indent more. But don't if the current line starts with "begin". // If the current line starts with "end", indent less, or maybe search // for its matching line and indent like that. do_verilog_indent() { int ind; save_var point; do { // Find prev non-comment line. if (!nl_reverse()) // First line in the file, no indent. return 0; to_begin_line(); } while (parse_string(1, "[ \t]*(--|\n)")); to_indentation(); ind = current_column(); restore_vars(); to_column(ind); } verilog_indenter() on verilog_tab['\t'] { int orig = point; int orig_column = current_column(); if (maybe_indent_rigidly(0)) return; to_indentation(); if (orig_column > current_column()) { /* if not in indentation */ point = orig; to_column(orig_column + verilog_indent - orig_column % verilog_indent); } else if (prev_cmd == C_INDENT) /* repeated, make bigger */ to_column(orig_column + verilog_indent); else { do_verilog_indent(); if (!get_indentation(point) && !orig_column && this_cmd != CMD_INDENT_REG) // 0 indent=>0 indent, to_column(verilog_indent); // but indent anyway } if (this_cmd != CMD_INDENT_REG) this_cmd = C_INDENT; } command verilog_mode() { mode_default_settings(); mode_keys = verilog_tab; /* Use these keys. */ major_mode = _verilog_mode_name; compile_buffer_cmd = compile_verilog_cmd; // can compile this indenter = do_verilog_indent; strcpy(comment_start, "(/)[ \t\f]*"); strcpy(comment_pattern, "//.*$|/<*>(.|)*<*>/"); strcpy(comment_begin, "// "); strcpy(comment_end, ""); recolor_range = color_verilog_range; // set up coloring rules recolor_from_here = recolor_from_top; if (want_code_coloring) // maybe turn on coloring when_setting_want_code_coloring(); if (auto_show_verilog_delimiters) auto_show_matching_characters = verilog_auto_show_delim_chars; buffer_maybe_break_line = generic_maybe_break_line; fill_mode = misc_language_fill_mode; try_calling("verilog-mode-hook"); drop_all_colored_regions(); make_mode(); } when_loading() { verilog_tab[ALT('q')] = (short) fill_comment; } suffix_v() { verilog_mode(); } suffix_tf() { verilog_mode(); } // Set display_func_name to the name of the function we're editing, and // return 1. If not in a function, set display_func_name to "" and // return 1. If user pressed a key and we gave up for now, return 0. verilog_func_name_finder() { int from, to, color, orig = point; char pat[FNAMELEN * 2]; save_var point, case_fold = 1; to_end_line(); recolor_buffer_range(0, point); while (re_search(-1, "^[ \t]*(module|task)[ \t]+([a-zA-Z_]*)")) { color = get_character_color(matchend); if (color == color_class vhdl_comment || color == color_class vhdl_string) continue; from = find_group(2, 1); to = find_group(2, 0); to = MIN(to, from + ptrlen(display_func_name) - 1); grab(from, to, display_func_name); point = matchstart; point += parse_string(1, "[ \t]*"); if (curchar() == '(') move_level(1, "(", ")", 0, 0); if (!parse_string(1, "[ \t]*(return[ \t\n]+[a-z0-9_]+[ \t]*)?is")) { point = from; continue; } if (matchend - matchstart < FNAMELEN) { sprintf(pat, "^[ \t]*end[ \t]+%s", display_func_name); if (re_search(1, pat) && point < orig) *display_func_name = 0; } return 1; } *display_func_name = 0; return 1; } tag_mode_verilog() { char func[TAGLEN]; int start, color; verilog_mode(); recolor_buffer_range(0, size()); // Just to skip over comments save_var point = 0, case_fold = 1; // & strings. while (re_search(1, "^[ \t]*(module|task|`define)[ \t]+([a-zA-Z_]*)")) { color = get_character_color(matchstart); if (color == color_class vhdl_comment || color == color_class vhdl_string) continue; grab(start = find_group(2, 1), find_group(2, 0), func); add_tag(func, start); } }