diff options
author | Andrej Shadura <andrewsh@debian.org> | 2018-05-08 15:59:29 +0200 |
---|---|---|
committer | Andrej Shadura <andrewsh@debian.org> | 2018-05-08 15:59:29 +0200 |
commit | 5b8466f7fae0e071c0f4eda13051c93313910028 (patch) | |
tree | 7061957f770e5e245ba00666dad912a2d44e7fdc /lib/editor/ASMsyntaxhighlight.tcl |
Import Upstream version 1.3.7
Diffstat (limited to 'lib/editor/ASMsyntaxhighlight.tcl')
-rwxr-xr-x | lib/editor/ASMsyntaxhighlight.tcl | 1675 |
1 files changed, 1675 insertions, 0 deletions
diff --git a/lib/editor/ASMsyntaxhighlight.tcl b/lib/editor/ASMsyntaxhighlight.tcl new file mode 100755 index 0000000..fe364d5 --- /dev/null +++ b/lib/editor/ASMsyntaxhighlight.tcl @@ -0,0 +1,1675 @@ +#!/usr/bin/tclsh +# Part of MCU 8051 IDE ( http://mcu8051ide.sf.net ) + +############################################################################ +# Copyright (C) 2007-2009 by Martin Ošmera # +# martin.osmera@gmail.com # +# # +# 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 # +# the Free Software Foundation; either version 2 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program; if not, write to the # +# Free Software Foundation, Inc., # +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # +############################################################################ + +# -------------------------------------------------------------------------- +# DESCRIPTION +# Implements syntax highlighting interface for assembly language +# -------------------------------------------------------------------------- + +namespace eval ASMsyntaxHighlight { + ## Highlight colors and font styles - highlight tags definition + # { + # {tag_name ?foreground? ?overstrike? ?italic? ?bold?} + # } + variable hightlight_tags { + {tag_char #880066 0 0 0} + {tag_hex #8800BB 0 0 0} + {tag_oct #880000 0 0 0} + {tag_dec #0055AA 0 0 0} + {tag_bin #333355 0 0 0} + {tag_constant #55AA00 0 0 0} + {tag_unknown_base #882222 0 0 0} + + {tag_string #888800 0 0 0} + {tag_comment #888888 0 1 0} + {tag_control #FF0000 0 0 1} + {tag_symbol #AA00FF 0 0 1} + {tag_oper_sep #DD8800 0 0 1} + {tag_directive #8888FF 0 0 1} + {tag_label #885500 0 0 0} + {tag_instruction #0000FF 0 0 1} + {tag_sfr #0000DD 0 0 0} + {tag_indirect #DD0000 0 0 0} + + {tag_imm_char #DD00AA 0 0 0} + {tag_imm_hex #AA00DD 0 0 0} + {tag_imm_oct #AA0000 0 0 0} + {tag_imm_dec #0088DD 0 0 0} + {tag_imm_bin #5555AA 0 0 0} + {tag_imm_constant #EFBC2B 0 0 0} + {tag_imm_unknown #AA3333 0 0 0} + + {tag_macro #CC00DD 0 0 1} + } + # Instructions keywords + variable instructions { + ACALL ADD ADDC AJMP ANL CJNE CLR CPL DA DEC DIV DJNZ INC JB JBC JC JMP JNB JNZ SJMP JNC CALL + JZ LCALL LJMP MOV MOVC MOVX MUL NOP ORL POP PUSH RET RETI RL RLC RR RRC SETB SUBB SWAP XCH XCHD XRL + } + # SFR bits + variable spec_bits { + C Z P OV RS0 RS1 F0 AC CY PX0 PT0 PX1 PT1 PS RXD TXD INT0 INT1 T0 T1 WR RD + EX0 ET0 EX1 ET1 ES EA RI TI RB8 TB8 REN SM2 SM1 SM0 IT0 IE0 IT1 IE1 TR0 TF0 TR1 TF1 + TF2 EXF2 RCLK TCLK EXEN2 TR2 CT2 CPRL2 EC PC ET2 PT2 FE + CR CCF4 CCF3 CCF2 CCF1 CCF0 PPCL PT2L PSL PT1L PX1L PT0L PX0L + } + # SFR registers and bits + variable spec_registers [concat { + A ACC B AB P0 P1 P2 P3 TL0 TL1 TH0 TH1 TMOD TCON SCON DPL PCON PSW SP DPH SBUF IE IP + R0 R1 R2 R3 R4 R5 R6 R7 DPTR DP0L DP0H + T2CON T2MOD RCAP2L RCAP2H TL2 TH2 AUXR1 WDTRST AUXR P4 DPH DPL DP1H DP1L + WDTCON EECON CLKREG ACSR IPH SADDR SADEN SPCR SPSR SPDR CKCON WDTPRG + + CH CCAP0H CCAP1H CCAPL2H CCAPL3H CCAPL4H ADCLK ADCON ADDL ADDH ADCF + CL CCAP0L CCAP1L CCAPL2L CCAPL3L CCAPL4L P1M2 P3M2 P4M2 + P1M1 P3M1 P4M1 SPCON SPSTA SPDAT CMOD CCAPM0 CCAPM1 CCAPM2 CCAPM3 CCAPM4 + IPL1 IPH1 IPH0 BRL BDRCON KBLS KBE KBF WDTRST WDTPRG CKRL CKCON0 IPL0 CCON + } $spec_bits] + + ## COMPILER DIRECTIVES + # directives without arguments + variable directive_type0 { + ENDIF ENDM END ELSE EXITM LIST NOLIST + } + + # directives with argument(s) but without any label + variable directive_type1 { + DSEG ISEG BSEG XSEG CSEG SKIP NAME + } + # directives for constants definitions + variable directive_type2 { + EQU BIT SET CODE DATA IDATA XDATA MACRO FLAG + } + # directives with argument and optional label + variable directive_type3 { + DS DW DB DBIT INCLUDE ORG IF USING BYTE NAME REPT TIMES + ELSEIF IFN ELSEIFN IFDEF ELSEIFDEF IFNDEF ELSEIFNDEF IFB ELSEIFB IFNB ELSEIFNB + } + # all known directives + variable all_directives [concat $directive_type0 $directive_type1 $directive_type2 $directive_type3] + # word operators + variable expr_instructions { + MOD SHR SHL NOT AND OR LE XOR EQ NE GT GE LT HIGH LOW + } + # symbol operators + variable expr_symbols { + = + - * / > < % + } + + # control sequencies without any argument + variable controls_type0 { + NOLIST NOMOD NOOBJECT NOPAGING NOPRINT + NOSYMBOLS EJECT LIST PAGING SYMBOLS NOMACROSFIRST + + NOXR NOXREF XR XREF NOSB SB RESTORE RS SA SAVE PHILIPS + NOPI PI NOTABS NOMOD51 NOBUILTIN NOMO MO MOD51 NOMACRO + NOMR LI NOLI GENONLY GO NOGEN NOGE GEN GE EJ NODB + NODEBUG DB DEBUG CONDONLY NOCOND COND + } + # control sequencies with exactly 1 argument + variable controls_type1 { + PAGEWIDTH PAGELENGTH PRINT TITLE OBJECT DATE INCLUDE + + TT PW PL MR MACRO INC WARNING ERROR DA + } + # all known control sequencies + variable all_controls [concat $controls_type0 $controls_type1] + # all known control sequencies with preceeding dolar character + variable all_controls__with_dolar + # all known directives and control sequencies + variable all_directives_and_controls [concat $all_directives $all_controls] + # list of all reserved keywords + variable keyword_lists [list \ + $instructions \ + $directive_type0 \ + $directive_type1 \ + $directive_type2 \ + $directive_type3 \ + ] + + variable inline_asm ;# Is inline assembler + variable editor ;# ID of the text widget + variable lineNumber ;# Number of current line + variable lineStart ;# Index of line start + variable lineEnd ;# Index of line end + variable data ;# Content of the line + variable data_backup ;# Original content of the line + variable last_index ;# Last parse index + variable last_index_backup ;# Auxiliary variable (some index) + + variable seg_0 ;# 1st field of the line + variable seg_1 ;# 2nd field of the line + variable seg_2 ;# 3rd field of the line + variable seg_0_start ;# Start index of seg_0 + variable seg_1_start ;# Start index of seg_1 + variable seg_2_start ;# Start index of seg_2 + variable seg_0_end ;# End index of seg_0 + variable seg_1_end ;# End index of seg_1 + variable seg_2_end ;# End index of seg_2 + + variable operands_count 0 ;# Number of operands at the line + variable operand ;# Data of the current operand + variable opr_end ;# End index of the current operand + variable opr_start ;# Start index of the current operand + + ## List of operand types on the line (eg. '{D # DPTR}') + # Possible values are: + # - '#' : Immediate addressing + # - @$x : Indirect addressing (one of {@R0 @R1 @DPTR @A+DPTR @A+PC}) + # - '/' : Inverted bit + # - 'D' : Direct addressing + # - $sfr : One of {R0 R1 R2 R3 R4 R5 R6 R7 DPTR A AB C} + variable opr_types + + variable validation_L0 1 ;# Bool: Basic validation enabled + variable validation_L1 1 ;# Bool: Advancet validation enabled + + ## Define highlighting text tags in the given text widget + # @parm Widget - ID of the target text widget + # @parm Int - font size + # @parm String - font family + # @parm List = default - Highlighting tags definition + # @return void + proc create_tags args { + variable hightlight_tags ;# Highlight tags definition + + # Handle arguments + set text_widget [lindex $args 0] ;# text widget + set fontSize [lindex $args 1] ;# font size + set fontFamily [lindex $args 2] ;# font family + if {[llength $args] > 3} { ;# highlighting definition + set hightlight [lindex $args 3] + } { + set hightlight $hightlight_tags + } + + # Iterate over highlighting tags definition + foreach item $hightlight { + # Create array of tag attributes + for {set i 0} {$i < 5} {incr i} { + set tag($i) [lindex $item $i] + } + + # Foreground color + if {$tag(1) == {}} { + set tag(1) black + } + # Fonr slant + if {$tag(3) == 1} { + set tag(3) italic + } { + set tag(3) roman + } + # Font weight + if {$tag(4) == 1} { + set tag(4) bold + } { + set tag(4) normal + } + + # Tag "tag_constant" is copied as "tag_constant_def" + #+ and "tag_macro" as "tag_macro_def" + if {$tag(0) == {tag_constant}} { + lappend tag(0) {tag_constant_def} + } elseif {$tag(0) == {tag_macro}} { + lappend tag(0) {tag_macro_def} + } + + # Create the tag in the target text widget + foreach tag_name $tag(0) { + $text_widget tag configure $tag_name \ + -foreground $tag(1) \ + -font [font create \ + -overstrike $tag(2) \ + -slant $tag(3) \ + -weight $tag(4) \ + -size -$fontSize \ + -family $fontFamily \ + ] + } + } + # Add tag error + $text_widget tag configure tag_error -underline 1 + } + + ## Perform syntax highlight on the given line in the given widget + # @parm Widget Editor - Text widget + # @parm Int LineNumber - Number of line to highlight + # @parm Bool inline_asm - Inline assembler + # @parm Int boundary_0 = 0 - Start index + # @parm Int boundary_1 = end - End index + # @return Bool - result + proc highlight args { + variable editor ;# ID of the text widget + variable lineNumber ;# Number of current line + variable lineStart ;# Index of line start + variable lineEnd ;# Index of line end + variable inline_asm ;# Is inline assembler + + variable seg_0 {} ;# 1st field of the line + variable seg_1 {} ;# 2nd field of the line + variable seg_2 {} ;# 3rd field of the line + variable seg_0_start ;# Start index of seg_0 + variable seg_1_start ;# Start index of seg_1 + variable seg_2_start ;# Start index of seg_2 + variable seg_0_end ;# End index of seg_0 + variable seg_1_end ;# End index of seg_1 + variable seg_2_end ;# End index of seg_2 + + variable last_index ;# Last parse index + variable data ;# Content of the line + variable operands_count ;# Number of operand in the line + variable validation_L0 ;# Bool: Basic validation enabled + + # Parse input arguments + set editor [lindex $args 0] + set lineNumber [lindex $args 1] + set inline_asm [lindex $args 2] + set lineStart [lindex $args 3] + set lineEnd [lindex $args 4] + if {$inline_asm == {}} { + set inline_asm 0 + } + if {$lineStart == {}} { + set lineStart $lineNumber.0 + } { + set lineStart $lineNumber.$lineStart + } + if {$lineEnd == {}} { + set lineEnd [$editor index "$lineStart lineend"] + } { + set lineEnd $lineNumber.$lineEnd + } + if {[lindex $args 3] != {}} { + set start_offset [lindex $args 3] + } { + set start_offset 0 + } + + set data [$editor get $lineStart $lineEnd] + set operands_count 0 + set opr_types {} + + if {$inline_asm} { + delete_tags + } + + # check if the line is not empty + if {[regexp {^\s*$} $data]} { + return 0 + } + set line_length [string length $data] + if {$line_length == 0} { + return 0 + } + + # determinate comment field and highlight it (the last field) + set comment_start {} + if {[regexp {;} $data]} { + + # remove 'string' from the line + set comment_data [hide_strings $data] + + if {[regexp {;.*$} $comment_data comment_start]} { + + set comment_start [string length $comment_start] + set comment_start [expr {$line_length - $comment_start}] + + # remove comment and trailing space from the line + if {$comment_start == 0} { + set data {} + delete_tags + } { + set data [string range $data 0 [expr {$comment_start - 1}]] + regsub {\s+$} $data {} data + } + + incr comment_start $start_offset + } + } + + # Handle line containing only comment + if {![string length $data]} { + if {!$inline_asm} { + delete_tags + } + $editor tag add tag_comment $lineNumber.$comment_start $lineEnd + return 1 + } + + # Determinate 1st segment of the line + regexp {^\s*[^\s:\(]+:?} $data seg_0 + set seg_0_end [string length $seg_0] + regsub {^\s+} $seg_0 {} seg_0 + + set seg_0_start [string length $seg_0] + set seg_0_start [expr {$seg_0_end - $seg_0_start}] + + set data [string replace $data 0 [expr {$seg_0_end - 1}]] + incr seg_0_end $start_offset + incr seg_0_start $start_offset + set last_index $seg_0_end + + # + # SYNTAX HIGHLIGHT + # + + # delete existing tags within the line + if {!$inline_asm} { + delete_tags + } + + # highlight comment + if {$comment_start != {}} { + $editor tag add tag_comment $lineNumber.$comment_start $lineEnd + } + # highlight 1st and 2nd field + set seg_0_info [parse_segment $seg_0_start $seg_0_end $seg_0] + + # Conditional parsing with validation + switch -- [lindex $seg_0_info 0] { + {control_0} {} + {control_1} {} + {control_incorrect} {} + {label} { + determinate_segment_1 + set seg_1_info [parse_segment $seg_1_start $seg_1_end $seg_1] + switch -- [lindex $seg_1_info 0] { + {control_0} { + determinate_segment_2 + put_error_on_segment 2 + } + {control_1} { + determinate_segment_2 + put_error_on_segment 2 + } + {label} { + put_error_on_segment 1 + } + {instruction} { + determinate_segment_2 + parse_operands + } + {directive_3} { + determinate_segment_2 + if {![string length $seg_2]} { + put_error_on_segment 1 + } + + set seg_1 [string tolower $seg_1] + if {$seg_1 == {db} || $seg_1 == {.db} || $seg_1 == {byte} || $seg_1 == {.byte}} { + parse_operands + } elseif {$seg_1 == {include} || $seg_1 == {.include}} { + $editor tag add tag_string \ + $lineNumber.$seg_2_start \ + [list $lineNumber.0 lineend] + } { + parse_expressions + } + } + {directive_2} { + put_error_on_segment 0 + } + {directive_1} {} + {directive_0} { + determinate_segment_2 + if {[string length $seg_2]} { + incr seg_2_end + put_error_on_segment 2 + } + } + {unknown} { + $editor tag add tag_macro \ + $lineNumber.$seg_1_start $lineNumber.$seg_1_end + if { + $validation_L0 && + ([regexp {^\d} $seg_1] || ![regexp {^\w+$} $seg_1]) + } { + put_error_on_segment 1 + } + determinate_segment_2 + parse_operands + } + default { + put_error_on_segment 1 + } + } + } + {instruction} { + determinate_segment_2 + parse_operands + } + {directive_3} { + determinate_segment_2 + if {![string length $seg_2]} { + put_error_on_segment 0 + } + + set seg_0 [string tolower $seg_0] + if {$seg_0 == {db} || $seg_0 == {.db} || $seg_0 == {byte} || $seg_0 == {.byte}} { + parse_operands + } elseif {$seg_0 == {include} || $seg_0 == {.include}} { + $editor tag add tag_string \ + $lineNumber.$seg_2_start \ + [list $lineNumber.0 lineend] + } { + parse_expressions + } + } + {directive_2} { + determinate_segment_2 + parse_expressions + put_error_on_segment 0 + } + {directive_1} { + determinate_segment_2 + parse_expressions + } + {directive_0} { + determinate_segment_1 + put_error_on_segment 1 + determinate_segment_2 + put_error_on_segment 2 + } + {unknown} { + determinate_segment_1 + set seg_1_info [parse_segment $seg_1_start $seg_1_end $seg_1] + switch -- [lindex $seg_1_info 0] { + {control_0} { + determinate_segment_2 + put_error_on_segment 2 + } + {control_1} { + determinate_segment_2 + put_error_on_segment 2 + } + {label} { + put_error_on_segment 0 + } + {instruction} { + put_error_on_segment 0 + determinate_segment_2 + parse_operands + } + {directive_3} { + put_error_on_segment 0 + determinate_segment_2 + set seg_1 [string tolower $seg_1] + if {$seg_1 == {db} || $seg_1 == {.db} || $seg_1 == {byte} || $seg_1 == {.byte}} { + parse_operands + } elseif {$seg_1 == {include} || $seg_1 == {.include}} { + $editor tag add tag_string \ + $lineNumber.$seg_2_start \ + [list $lineNumber.0 lineend] + } { + parse_expressions + } + } + {directive_2} { + if { + $validation_L0 && + ([regexp {^\d} $seg_0] || ![regexp {^\w+$} $seg_0]) + } { + put_error_on_segment 0 + } + + set sg [string tolower $seg_1] + if {$sg == {macro} || $sg == {.macro}} { + $editor tag add tag_macro_def \ + $lineNumber.$seg_0_start \ + $lineNumber.$seg_0_end + determinate_segment_2 + parse_arguments + } { + $editor tag add tag_constant_def \ + $lineNumber.$seg_0_start \ + $lineNumber.$seg_0_end + + determinate_segment_2 + parse_expressions + } + } + {directive_1} { + put_error_on_segment 0 + determinate_segment_2 + parse_expressions + } + {directive_0} { + put_error_on_segment 0 + determinate_segment_2 + put_error_on_segment 2 + } + {unknown} { + $editor tag add tag_macro $lineNumber.$seg_0_start $lineNumber.$seg_0_end + if { + $validation_L0 && + ([regexp {^\d} $seg_0] || ![regexp {^\w+$} $seg_0]) + } { + put_error_on_segment 0 + } + determinate_segment_1_take_back + determinate_segment_2 + parse_operands + } + default { + $editor tag add tag_macro $lineNumber.$seg_0_start $lineNumber.$seg_0_end + if { + $validation_L0 && + ([regexp {^\d} $seg_0] || ![regexp {^\w+$} $seg_0]) + } { + put_error_on_segment 0 + } + } + } + } + default {} + } + + return 1 + } + + ## Remove previously defined syntax highlighting tags + # @return void + proc delete_tags {} { + variable editor ;# ID of the text widget + variable hightlight_tags ;# Highlight tags definition + variable lineStart ;# Index of line start + variable lineEnd ;# Index of line end + + set lineStart_truestart [$editor index [list $lineStart linestart]] + + # Remove tag error, tag_constant_def and tag_macro_def + foreach tag {tag_error tag_constant_def tag_macro_def} { + $editor tag remove $tag $lineStart_truestart $lineStart_truestart+1l + } + + # Remove tags acording to pattern + foreach tag $hightlight_tags { + $editor tag remove [lindex $tag 0] $lineStart_truestart $lineEnd + } + } + + ## Take back extraction of segment 1 + # @return void + proc determinate_segment_1_take_back {} { + variable data ;# Content of the line + variable data_backup ;# Original content of the line + variable last_index ;# Last parse index + variable last_index_backup ;# Auxiliary variable (some index) + + set data $data_backup + set last_index $last_index_backup + } + + ## Extract segment 1 from the line + # @return void + proc determinate_segment_1 {} { + variable seg_1 ;# 2nd field of the line + variable seg_1_start ;# Start index of seg_1 + variable seg_1_end ;# End index of seg_1 + variable last_index ;# Last parse index + variable data ;# Content of the line + variable data_backup ;# Original content of the line + variable last_index_backup ;# Auxiliary variable (some index) + + # Line is empty + if {![regexp {^\s*[^\s\(]+} $data seg_1]} { + set seg_1 {} + set seg_1_end $last_index + set seg_1_start $last_index + + # Line is not empty + } { + set data_backup $data + set last_index_backup $last_index + + set seg_1_end [string length $seg_1] + set data [string replace $data 0 [expr {$seg_1_end - 1}]] + incr seg_1_end $last_index + + regsub {^\s+} $seg_1 {} seg_1 + set seg_1_start [string length $seg_1] + set seg_1_start [expr {$seg_1_end - $seg_1_start}] + + set last_index $seg_1_end + } + } + + ## Extract segment 2 from the line + # @return void + proc determinate_segment_2 {} { + variable seg_2 ;# 3rd field of the line + variable seg_2_start ;# Start index of seg_2 + variable seg_2_end ;# End index of seg_2 + variable last_index ;# Last parse index + variable data ;# Content of the line + + # determinate the last segment of the line + set seg_2_start $last_index + if {[regexp {^\s+} $data space]} { + incr seg_2_start [string length $space] + } + regsub {^\s+} $data {} seg_2 + regsub {\s+$} $seg_2 {} seg_2 + set seg_2_end [string length $seg_2] + incr seg_2_end $last_index + set data {} + } + + ## Shorthand for 'parse_expression $seg_2 $seg_2_start $seg_2_end' + # @return void + proc parse_expressions {} { + variable seg_2 ;# 3rd field of the line + variable seg_2_start ;# Start index of seg_2 + variable seg_2_end ;# End index of seg_2 + + parse_expression $seg_2 $seg_2_start $seg_2_end + } + + ## Parse given segment, highlight it and determinate its type + # @parm Int start - start column + # @parm int end - end column + # @parm String segment_data - content of segment to parse + # @return List - {segment_type expression_length} or {segment_type {}} or {{} {}} + proc parse_segment {start end segment_data} { + variable controls_type0 ;# control sequencies without any argument + variable controls_type1 ;# control sequencies with exactly 1 argument + + variable keyword_lists ;# list of all reserved keywords + variable editor ;# ID of the text widget + variable lineNumber ;# Number of current line + variable lineStart ;# Index of line start + variable lineEnd ;# Index of line end + variable data ;# Content of the line + variable validation_L0 ;# Bool: Basic validation enabled + + # Local variables + set seg_type {} ;# segment type + set expr_len 0 ;# length of expression + + # Handle empty segments + if {$segment_data == {}} { + return [list $seg_type $expr_len] + } + + # Convert segment data to uppre case (patterns are uppper-case) + set segment_data [string toupper $segment_data] + + # Try to determinate segment type and perform highlight + set keyword $segment_data + if {[string index $keyword 0] == {.}} { + set keyword [string replace $keyword 0 0] + } + foreach keyword_list $keyword_lists \ + tag {tag_instruction tag_directive tag_directive tag_directive tag_directive} \ + type {instruction directive_0 directive_1 directive_2 directive_3} { + if {$type != {instruction}} { + if {[lsearch -ascii -exact $keyword_list $keyword] != -1} { + $editor tag add $tag $lineNumber.$start $lineNumber.$end + set seg_type $type + break + } + } { + if {[lsearch -ascii -exact $keyword_list $segment_data] != -1} { + $editor tag add $tag $lineNumber.$start $lineNumber.$end + set seg_type $type + break + } + } + } + + # If segment type could not be recognized -> check for labels, macro's and controls + if {$seg_type == {}} { + + # Handle compiler control sequences + if {[string index $segment_data 0] == {$}} { + set segment_data [string range $segment_data 1 end] + set expr_data {} + + set segment_data "$segment_data $data" + set segment_data [string trimright $segment_data { }] + set end [string length $segment_data] + incr end [expr {$start + 1}] + set ctrl_end $end + set data {} + if {[regexp {\(.*$} $segment_data expr_data]} { + set expr_len [string length $expr_data] + set expr_start [expr {$end - $expr_len - 1}] + set expr_end [expr {$expr_start + $expr_len}] + set end $expr_start + regsub {\(.*$} $segment_data {} segment_data + set segment_data [string trimright $segment_data] + } + + # Control type 1 + if {[lsearch -ascii -exact $controls_type1 $segment_data] != -1} { + set seg_type control_1 + # Control type 0 + } elseif {[lsearch -ascii -exact $controls_type0 $segment_data] != -1} { + set seg_type control_0 + # Incorrect control sequence + } else { + set seg_type control_incorrect + if {$validation_L0} { + $editor tag add tag_error $lineNumber.$start $lineNumber.$end + } + } + + # Puts tag "control" + $editor tag add tag_control $lineNumber.$start $lineNumber.$end + + # Control sequence argument + if {$expr_data != {}} { + parse_argument $expr_start $expr_end $expr_data $start $end + if {$validation_L0 && $seg_type == {control_0}} { + $editor tag add tag_error $lineNumber.$expr_start $lineNumber.$expr_end + } + } elseif {$validation_L0 && $seg_type == {control_1}} { + $editor tag add tag_error $lineNumber.$start $lineNumber.$end + } + + # Labels + } elseif {[regexp -nocase {^\w+:$} $segment_data]} { + $editor tag add tag_label $lineNumber.$start $lineNumber.$end + set seg_type label + + # Unknown type - possibly macro instruction + } { + set seg_type unknown + } + } + + # Return result + return [list $seg_type $expr_len] + } + + ## Highlight argument (eg. '("some string")') + # @parm Int start_index - start column of the argument + # @parm Int end_index - end column of the argument + # @parm String data - argument data + # @return void + proc parse_argument {start_index end_index data control_start control_end} { + variable editor ;# ID of the text widget + variable lineNumber ;# Number of current line + variable validation_L0 ;# Bool: Basic validation enabled + + if {[regexp {^\(.*\)$} $data]} { + $editor tag add tag_symbol $lineNumber.$start_index $lineNumber.[expr {$start_index + 1}] + set end [expr {$end_index - 1}] + $editor tag add tag_symbol $lineNumber.$end $lineNumber.$end_index + + $editor tag add tag_string $lineNumber.[expr {$start_index + 1}] $lineNumber.$end + } { + if {$validation_L0} { + $editor tag add tag_error \ + $lineNumber.$control_start $lineNumber.$control_end + } + } + } + + ## Tag the given segment as error + # @parm Int segment_number - number of the target segment + # @return void + proc put_error_on_segment {segment_number} { + variable editor ;# ID of the text widget + variable lineNumber ;# Number of current line + variable validation_L0 ;# Bool: Basic validation enabled + variable seg_0_start ;# Start index of seg_0 + variable seg_1_start ;# Start index of seg_1 + variable seg_2_start ;# Start index of seg_2 + variable seg_0_end ;# End index of seg_0 + variable seg_1_end ;# End index of seg_1 + variable seg_2_end ;# End index of seg_2 + + if {!$validation_L0} { + return + } + + # Determinate start and end index + switch -- $segment_number { + 0 { + set start $seg_0_start + set end $seg_0_end + } + 1 { + set start $seg_1_start + set end $seg_1_end + } + 2 { + set start $seg_2_start + set end $seg_2_end + } + } + + # Add error tag + $editor tag add tag_error $lineNumber.$start $lineNumber.$end + } + + ## Parse attributes in defintion of macro instruction + # @retunr void + proc parse_arguments {} { + variable editor ;# ID of the text widget + variable lineNumber ;# Number of current line + variable seg_2_start ;# Start index of seg_2 + variable seg_2 ;# 3rd field of the line + variable validation_L0 ;# Bool: Basic validation enabled + + if {[regexp {^\s*$} $seg_2]} {return 0} + + while 1 { + # Handle redutant commas + while 1 { + if {![regexp {^\s*\,} $seg_2]} {break} + + set space_len 0 + if {[regexp {^\s+} $seg_2 space_len]} { + set space_len [string length $space_len] + } + + incr seg_2_start $space_len + set seg_2 [string range $seg_2 [expr {$space_len + 1}] end] + + $editor tag add tag_oper_sep \ + $lineNumber.$seg_2_start \ + $lineNumber.[expr {$seg_2_start + 1}] + + if {$validation_L0} { + $editor tag add tag_error \ + $lineNumber.$seg_2_start \ + $lineNumber.[expr {$seg_2_start + 1}] + } + + incr seg_2_start + } + + # Determinate argument + if {![regexp {^[^\,]+} $seg_2 argument]} {break} + set argument_len_org [string length $argument] + set seg_2 [string range $seg_2 $argument_len_org end] + set argument [string trimleft $argument] + set argument_len [string length $argument] + incr seg_2_start [expr {$argument_len_org - $argument_len}] + + # Highlight argument + $editor tag add tag_constant \ + $lineNumber.$seg_2_start \ + $lineNumber.[expr {$seg_2_start + $argument_len}] + set argument [string trimright $argument] + if {$validation_L0 && ([regexp {^\d} $argument] || ![regexp {^\w+$} $argument])} { + $editor tag add tag_error \ + $lineNumber.$seg_2_start \ + $lineNumber.[expr {$seg_2_start + $argument_len}] + } + + incr seg_2_start $argument_len + + # highlight argument separator + if {[string index $seg_2 0] == {,}} { + set sep_end $seg_2_start + incr sep_end + $editor tag add tag_oper_sep $lineNumber.$seg_2_start $lineNumber.$sep_end + if {$validation_L0 && ![regexp {[\w$]} $seg_2]} { + $editor tag add tag_error $lineNumber.$seg_2_start $lineNumber.$sep_end + } + incr seg_2_start + set seg_2 [string range $seg_2 1 end] + } + } + } + + ## Highlight all operands (segment 2) and their separators + # @return void + proc parse_operands {} { + variable editor ;# ID of the text widget + variable lineNumber ;# Number of current line + variable seg_2_start ;# Start index of seg_2 + variable seg_2 ;# 3rd field of the line + + variable operands_count ;# Number of operands at the line + variable operand ;# Data of the current operand + variable opr_end ;# End index of the current operand + variable opr_start ;# Start index of the current operand + + variable opr_types ;# List of operand types + variable validation_L0 ;# Bool: Basic validation enabled + variable validation_L1 ;# Bool: Advancet validation enabled + + if {[regexp {^\s*$} $seg_2]} {return 0} + set operands_count 0 + set opr_types {} + + # split data into single operands + set i 0 + set last_index $seg_2_start + set original_data $seg_2 + set data [hide_strings $seg_2] + + while 1 { + # Handle redutant commas + while 1 { + if {![regexp {^\s*\,} $data]} {break} + + set space_len 0 + if {[regexp {^\s+} $data space_len]} { + set space_len [string length $space_len] + } + incr last_index $space_len + + set data [string range $data [expr {$space_len + 1}] end] + set original_data [string range $original_data [expr {$space_len + 1}] end] + + $editor tag add tag_oper_sep \ + $lineNumber.$last_index \ + $lineNumber.[expr {$last_index + 1}] + + if {$validation_L0} { + $editor tag add tag_error \ + $lineNumber.$last_index \ + $lineNumber.[expr {$last_index + 1}] + } + + incr last_index + } + + # gain operand data + if {![regexp {^[^\,]+} $data operand]} {break} + set operand_len [string length $operand] + set data [string range $data $operand_len end] + set operand [string range $original_data 0 [expr {$operand_len - 1}]] + set original_data [string range $original_data $operand_len end] + + # determinate start index + if {[regexp {^\s+} $operand space]} { + set space_len [string length $space] + set opr_start [expr {$last_index + $space_len}] + set operand [string range $operand $space_len end] + } { + set opr_start $last_index + } + + # determinate end index + if {[regexp {\s+$} $operand space]} { + set space_len [string length $space] + set opr_end [expr {$operand_len - $space_len}] + set operand [string range $operand 0 $opr_end] + } { + set opr_end $operand_len + } + incr opr_end $last_index + incr last_index $operand_len + + set operand [string trimright $operand "\t "] + if {$validation_L1} { + add_aperand_to__opr_types + } + highlight_operand + incr operands_count + + # highlight operand separator + if {[string index $data 0] == {,}} { + set sep_end $last_index + incr sep_end + $editor tag add tag_oper_sep $lineNumber.$last_index $lineNumber.$sep_end + if {$validation_L0 && ![regexp {[\w$]} $data]} { + $editor tag add tag_error $lineNumber.$last_index $lineNumber.$sep_end + } + incr last_index + set data [string range $data 1 end] + set original_data [string range $original_data 1 end] + } + + incr i + } + } + + ## Append current operand (var. operand) to list of operand types + #+ on current line + # @return void + proc add_aperand_to__opr_types {} { + variable opr_types ;# List of operand types + variable operand ;# Data of the current operand + + set opr [string toupper $operand] + + switch -- [string index $opr 0] { + {#} {lappend opr_types {#}} + {/} {lappend opr_types {/}} + {@} {lappend opr_types $opr} + default { + if {[lsearch -ascii -exact {R0 R1 R2 R3 R4 R5 R6 R7 DPTR A AB C} $opr] != -1} { + lappend opr_types $opr + } { + lappend opr_types {D} + } + } + } + } + + ## Highlight current operand + # @return void + proc highlight_operand {} { + variable editor ;# ID of the text widget + variable operand ;# Data of the current operand + variable opr_end ;# End index of the current operand + variable opr_start ;# Start index of the current operand + variable spec_registers ;# SFR registers + variable spec_bits ;# SFR bits + variable validation_L0 ;# Bool: Basic validation enabled + variable inline_asm ;# Is inline assembler + variable lineNumber ;# Number of current line + + ## Determinate addressing type + set addr_type [string index $operand 0] + + # Immediate adresing + if {$addr_type == {#}} { + set operand [string range $operand 1 end] + + # Immediate char value + if {[string index $operand 0] == {'} && [string index $operand end] == {'}} { + set len [string length $operand] + if {$validation_L0 && $len < 3} { + put_tag_on_operand tag_error + } + if {$len > 3} { + put_tag_on_operand tag_string + } { + put_tag_on_operand tag_imm_char + } + + # Label in inline assembler + } elseif {[regexp {^\d+\$$} $operand]} { + put_tag_on_operand tag_imm_constant + + # Operand has no value => incorrect operand + } elseif {[regexp { |\(|\)|\+|\-|\%|\=|\>|\<|\*|\/} $operand]} { + parse_expression $operand $opr_start $opr_end + $editor tag add tag_symbol \ + $lineNumber.$opr_start $lineNumber.$opr_start+1c + + } elseif { + $validation_L0 && + ([string length $operand] == 0 || ![regexp {^[\w\$\.\\]+$} $operand]) + } { + put_tag_on_operand tag_error + + # Operand value determinated successfully + } else { + parse_operand_auxiliary2 { + tag_imm_unknown tag_imm_hex tag_imm_dec + tag_imm_oct tag_imm_bin tag_imm_char + tag_imm_constant tag_string + } + } + + # Indirect adresing + } elseif {$addr_type == {@}} { + set operand [string range $operand 1 end] + put_tag_on_operand tag_indirect + + # Check for operand validity + if {!$validation_L0} {return} + set operand [string toupper $operand] + if { + $operand != {R0} && + $operand != {R1} && + $operand != {DPTR} && + $operand != {A+PC} && + $operand != {A+DPTR} + } { + put_tag_on_operand tag_error + } + + # Direct bit adresing + } elseif {$addr_type == {/}} { + set operand [string range $operand 1 end] + + if {[regexp {\(|\)|\+|\-|\%|\=|\>|\<|\*|\/} $operand]} { + parse_expression $operand $opr_start $opr_end + $editor tag add tag_symbol \ + $lineNumber.$opr_start $lineNumber.$opr_start+1c + + } elseif { + $validation_L0 && + ([string length $operand] == 0 || ![regexp {^'?[\w\.]+'?$} $operand]) + } { + + # Operand has no value => incorrect operand + put_tag_on_operand tag_error + + } else { + parse_operand_auxiliary $spec_bits { + tag_unknown_base tag_hex tag_dec + tag_oct tag_bin tag_char + tag_constant tag_string + } + } + + # Another kind of direct adresing + } else { + parse_operand_auxiliary $spec_registers { + tag_unknown_base tag_hex tag_dec + tag_oct tag_bin tag_char + tag_constant tag_string + } + } + } + + ## Auxiliary procedure for procedure highlight_operand + # @parm List SFR_set - List of SFR keywords + # @parm List tag_list - List of tags for procedure parse_operand_auxiliary2 + # @return void + proc parse_operand_auxiliary {SFR_set tag_list} { + variable operand ;# Data of the current operand + + # SFR + if {[lsearch -ascii -exact $SFR_set [string toupper $operand]] != -1} { + put_tag_on_operand tag_sfr + + # Something else than SFR + } { + parse_operand_auxiliary2 $tag_list + } + } + + ## Auxiliary procedure for procedures highlight_operand and parse_operand_auxiliary + # @parm List tag_list - list of text tags (see code) + # @return void + proc parse_operand_auxiliary2 {tag_list} { + variable operand ;# Data of the current operand + variable opr_start ;# Start index of the current operand + variable opr_end ;# End index of the current operand + variable editor ;# ID of the text widget + variable lineNumber ;# Number of current line + variable spec_registers ;# SFR registers + variable validation_L0 ;# Bool: Basic validation enabled + variable inline_asm ;# Is inline assembler + + # Label in inline assembler + if {$inline_asm && [regexp {^\d+\$$} $operand]} { + put_tag_on_operand [lindex $tag_list 6] + + # Expression + } elseif {[regexp {\(|\)|\+|\-|\%|\=|\>|\<|\*|\/} $operand]} { + parse_expression $operand $opr_start $opr_end + + # Dot notation (bit addressing) + } elseif {[regexp {^\w+\.\w+$} $operand]} { + set opr [split $operand {.}] + set operand [lindex $opr 0] + + set opr_true_end $opr_end + set opr_end $opr_start + incr opr_end [string length $operand] + + parse_operand_auxiliary $spec_registers $tag_list + + set opr_start [expr {$opr_end + 1}] + $editor tag add tag_symbol $lineNumber.$opr_end $lineNumber.$opr_start + + set opr_end $opr_true_end + set operand [lindex $opr 1] + + parse_operand_auxiliary2 $tag_list + + # Direct value + } elseif {[regexp {^(\d|')} $operand]} { + # gain information about the openand (radix and decimal value) + set opr_info [which_radix 0 $operand] + set opr_base [lindex $opr_info 0] + set opr_in_dec [lindex $opr_info 1] + + # Radix determinated incorrectly => unknown number + if {$opr_base == {}} { + put_tag_on_operand [lindex $tag_list 0] + + if {$validation_L0 && ![regexp {^\d+$} $operand]} { + put_tag_on_operand tag_error + } + + # Radix determinated correctly - continue normaly + } { + # check for allowed operand value range + if {$validation_L0 && $opr_in_dec == {error}} { + + ## Operand value is invalid => incorrect operand + put_tag_on_operand tag_error + + } { + if {$validation_L0 && ($opr_in_dec > 65535 || $opr_in_dec < 0)} { + + ## Operand value is out of range => incorrect operand + put_tag_on_operand tag_error + } + } + + # highlight acording to numeric base + switch -- $opr_base { + {hex} {put_tag_on_operand [lindex $tag_list 1]} + {dec} {put_tag_on_operand [lindex $tag_list 2]} + {oct} {put_tag_on_operand [lindex $tag_list 3]} + {bin} {put_tag_on_operand [lindex $tag_list 4]} + {ascii} {put_tag_on_operand [lindex $tag_list 5]} + {string} {put_tag_on_operand [lindex $tag_list 7]} + } + } + + # defined by a symbolic name + } { + put_tag_on_operand [lindex $tag_list 6] + if { + $validation_L0 && ($operand != {$}) && ![regexp {^\w+$} $operand] + } { + put_tag_on_operand tag_error + } + } + } + + ## Highlight current operand by the given tag + # @parm String tag_name - tag name + # @return void + proc put_tag_on_operand {tag_name} { + variable lineNumber ;# Number of current line + variable opr_end ;# End index of the current operand + variable opr_start ;# Start index of the current operand + variable editor ;# ID of the text widget + + $editor tag add $tag_name $lineNumber.$opr_start $lineNumber.$opr_end + } + + ## Determinate numeric base of the given number + # @parm Bool norange - 1 == determinate decimal value (sometimes...) and validate it (see code) + # @parm String number - number to analyze + # @return List - {base decimal_value} or {base "error"} + proc which_radix {norange number} { + set original_len [string length $number] + set len [string length [string trimleft $number {0}]] + if {$original_len > 1 && $len == 1} { + incr len + } + incr len -1 + set radix [string index $number end] + set number [string range $number 0 {end-1}] + set dec_val error + set base {} + + # Character or string + if {$radix == {'}} { + if {[string index $number 0] == {'}} { + set number [string range $number 1 end] + + set base ascii + if {[string length $number] == 1} { + set dec_val 0 + + } elseif {[string length $number] > 1} { + set base string + set dec_val 0 + } + } + + # Regular numbers + } else { + set radix [string tolower $radix] + switch -- $radix { + {h} { ;# Hexadecimal + set base hex + if {$norange || ($len <= 4 && $len >= 1)} { + if {[regexp {^[A-Fa-f0-9]*$} $number]} { + set dec_val 0 + } + } + } + {d} { ;# Decimal + set base dec + if {$norange || ($len <= 5 && $len >= 1)} { + if {[regexp {^[0-9]*$} $number]} { + set dec_val $number + } + } + } + {o} { ;# Octal + set base oct + if {$norange} { + if {[regexp {^[0-7]*$} $number]} { + set dec_val 0 + } + } elseif {$len <= 6 && $len >= 1} { + if {[regexp {^[0-7]*$} $number]} { + if {$len != 3} { + set dec_val 0 + } { + if {[string index $number 0] <= 3} { + set dec_val 0 + } + } + } + } + } + {q} { ;# Octal + set base oct + if {$norange} { + if {[regexp {^[0-7]*$} $number]} { + set dec_val 0 + } + } elseif {$len <= 6 && $len >= 1} { + if {[regexp {^[0-7]*$} $number]} { + if {$len != 3} { + set dec_val 0 + } { + if {[string index $number 0] <= 3} { + set dec_val 0 + } + } + } + } + } + {b} { ;# Binary + set base bin + if {$norange || ($len <= 16 && $len >= 1)} { + if {[regexp {^[01]*$} $number]} { + set dec_val 0 + } + } + } + default { ;# Default + set dec_val {} + } + } + } + + # done ... + return "$base $dec_val" + } + + ## Highlight expressions (eg. '( 10d - X MOD 55h)') + # @parm String data - expression to highlight + # @parm Int start_index - expresssion start index + # @parm Int end_index - expresssion end index + # @return void + proc parse_expression {data start_index end_index} { + + variable editor ;# ID of the text widget + variable lineNumber ;# Number of current line + variable expr_symbols ;# symbol operators + variable expr_instructions ;# word operators + variable validation_L0 ;# Bool: Basic validation enabled + variable validation_L1 ;# Bool: Advancet validation enabled + + # Adjust data to fit the given boundaries + set data_len [string length $data] + set dif [expr {$end_index - $start_index - $data_len}] + if {$dif != 0} { + set space [string repeat { } $dif] + set data $space$data + } + + # Remove strings + set e_idx 0 + while 1 { + if {![regexp -start $e_idx -- {'[^']*'} $data string_data]} { + break + } + set len [string length $string_data] + set s_idx [string first {'} $data $e_idx] + set e_idx [expr {$s_idx + $len}] + + if {$len > 2} { + set data [string replace $data \ + [expr {$s_idx + 1}] [expr {$e_idx - 2}] \ + [string repeat { } [expr {$len - 2}]] \ + ] + } + } + + # remove and highlight '(' + set opended_par 0 + while 1 { + set symbol_idx [string first {(} $data] + if {$symbol_idx == -1} {break} + + incr opended_par + set data [string replace $data $symbol_idx $symbol_idx { }] + incr symbol_idx $start_index + $editor tag add tag_symbol $lineNumber.$symbol_idx $lineNumber.[expr {$symbol_idx + 1}] + } + # remove and highlight ')' + while 1 { + set symbol_idx [string first {)} $data] + if {$symbol_idx == -1} {break} + + incr opended_par -1 + set data [string replace $data $symbol_idx $symbol_idx { }] + incr symbol_idx $start_index + $editor tag add tag_symbol $lineNumber.$symbol_idx $lineNumber.[expr {$symbol_idx + 1}] + } + # chcek if parenthesies are balanced + if {$validation_L0 && $opended_par != 0} { + $editor tag add tag_error $lineNumber.$start_index $lineNumber.$end_index + } + + # Highlight exprression symbols (+1 chars) and remove them from the string + set adjusted_data [string toupper $data] + regsub -all {\t} $adjusted_data { } adjusted_data + append adjusted_data { } + foreach symbol $expr_instructions { + while 1 { + set symbol_idx [string first " $symbol " $adjusted_data] + if {$symbol_idx == -1} {break} + set original_symbol_idx $symbol_idx + + set space_len [string length $symbol] + incr space_len 1 + set symbol_end_index $symbol_idx + incr symbol_end_index $space_len + set symbol_end_index_org_1 [expr {$symbol_end_index + 1}] + + incr space_len + set space [string repeat { } $space_len] + set adjusted_data [string replace $adjusted_data $symbol_idx $symbol_end_index $space] + set data [string replace $data $symbol_idx $symbol_end_index $space] + + incr symbol_idx $start_index + incr symbol_end_index $start_index + $editor tag add tag_symbol $lineNumber.$symbol_idx $lineNumber.$symbol_end_index + + if {$validation_L1} { + set tmp [string range $data $symbol_end_index_org_1 end] + set tmp [string toupper [string trim $tmp]] + if {![string length $tmp]} { + $editor tag add tag_error \ + $lineNumber.[expr {$symbol_idx + 1}] \ + $lineNumber.$symbol_end_index + } { + foreach smb $expr_instructions { + if {![string first $smb $tmp]} { + $editor tag add tag_error \ + $lineNumber.[expr {$symbol_idx + 1}] \ + $lineNumber.$symbol_end_index + break + } + } + } + } + } + } + # Highlight expression symbols (1 char) and remove them from the string + foreach symbol $expr_symbols { + while 1 { + set symbol_idx [string first $symbol $data] + if {$symbol_idx == -1} {break} + set original_symbol_idx $symbol_idx + set symbol_idx_org_1 [expr {$symbol_idx + 1}] + + set data [string replace $data $symbol_idx $symbol_idx { }] + incr symbol_idx $start_index + set symbol_idx_1 [expr {$symbol_idx + 1}] + $editor tag add tag_symbol $lineNumber.$symbol_idx $lineNumber.$symbol_idx_1 + + if { + $validation_L0 && ( + !$original_symbol_idx + || + ![regexp {^\s*((\'\\?[^']\')|\w|\$)} [string range $data $symbol_idx_org_1 end]] + ) + } { + $editor tag add tag_error \ + $lineNumber.$symbol_idx \ + $lineNumber.$symbol_idx_1 + } + } + } + + # Highlight other parts + set last_index $start_index + set original_data $data + set data [hide_strings $data] + while 1 { + + if {![regexp {[^\s]+} $data value]} {break} + + set value_S_idx [string first $value $data] + set value_len [string length $value] + set value_E_idx $value_len + incr value_E_idx $value_S_idx + + set value [string range $original_data $value_S_idx $value_E_idx] + + set data [string range $data $value_E_idx end] + set original_data [string range $original_data $value_E_idx end] + + set tmp_idx $value_E_idx + incr value_S_idx $last_index + incr value_E_idx $last_index + incr last_index $tmp_idx + + highlight_value [string trimright $value] $value_S_idx $value_E_idx + } + } + + ## Highlight constant values + # @parm String data - string to highlight + # @parm Int start_index - start index + # @parm Int end_index - end index + # @return void + proc highlight_value {data start_index end_index} { + variable editor ;# ID of the text widget + variable lineNumber ;# Number of current line + variable validation_L0 ;# Bool: Basic validation enabled + variable spec_registers ;# SFR registers + + # Dot notation -- bit addressing + if {[regexp {^\w+\.\w+$} $data]} { + set data [split $data {.}] + + set end_index_org $end_index + set end_index $start_index + incr end_index [string length [lindex $data 0]] + highlight_value [lindex $data 0] $start_index $end_index + + $editor tag add tag_symbol $lineNumber.$end_index $lineNumber.[expr {$end_index + 1}] + + incr end_index + highlight_value [lindex $data 1] $end_index $end_index_org + return + + } elseif {[regexp {^(\d|')} $data]} { + # Gain information about the value + set opr_info [which_radix 1 $data] + set opr_base [lindex $opr_info 0] + set opr_in_dec [lindex $opr_info 1] + + # Highlight value acording to info + if {$opr_base == {}} { + $editor tag add tag_unknown_base $lineNumber.$start_index $lineNumber.$end_index + if {$validation_L0 && ![regexp {^[0-9A-Fa-f]+$} $data]} { + $editor tag add tag_error $lineNumber.$start_index $lineNumber.$end_index + } + return + } + if {$validation_L0 && $opr_in_dec == {error}} { + $editor tag add tag_error $lineNumber.$start_index $lineNumber.$end_index + } + + # Highlight acording to numeric base + switch -- $opr_base { + {hex} { ;# Hexadecimal + $editor tag add tag_hex $lineNumber.$start_index $lineNumber.$end_index + } + {dec} { ;# Decimal + $editor tag add tag_dec $lineNumber.$start_index $lineNumber.$end_index + } + {oct} { ;# Octal + $editor tag add tag_oct $lineNumber.$start_index $lineNumber.$end_index + } + {bin} { ;# Binary + $editor tag add tag_bin $lineNumber.$start_index $lineNumber.$end_index + } + {ascii} { ;# Char + $editor tag add tag_char $lineNumber.$start_index $lineNumber.$end_index + } + {string} { ;# String + $editor tag add tag_string $lineNumber.$start_index $lineNumber.$end_index + } + } + return + } + + # Constant + if {[lsearch -ascii -exact $spec_registers [string toupper $data]] != -1} { + set tag tag_sfr + } { + set tag tag_constant + } + $editor tag add $tag $lineNumber.$start_index $lineNumber.$end_index + if {$validation_L0 && ![regexp {^((\w+)|\$)$} $data]} { + $editor tag add tag_error $lineNumber.$start_index $lineNumber.$end_index + } + } + + ## Replace all single quoted string with underscores (''abc'' -> '_____') + # @parm String data - input data + # @return String - output data + proc hide_strings {data} { + # Return string which dowsn't contain ''' + if {[string first {'} $data] == -1} {return $data} + + # Perform replacement + while 1 { + if {![regexp {'[^']*'} $data string]} { + break + } + regsub {'[^']*'} $data [string repeat {_} \ + [string length $string] \ + ] data + } + + # Return result + return $data + } +} + +# Initialize some namespace variables +foreach item ${::ASMsyntaxHighlight::all_controls} { + lappend ::ASMsyntaxHighlight::all_controls__with_dolar "\$$item" +} |