sanity.bac
' SANITY program to check (large) BaCon programs. PvE Nov 2014 - GPL.
'
' Though a BaCon program may compile, it still may contain memory leaks, loose ends
' or redundant code. This should be detected by the below program.
'
' Currently, the following checks are implemented:
'
' - MEMORY / FREE pairs
' - OPEN / CLOSE pairs
' - Unused SUBS/FUNCTIONS
' - Duplicate or unused IMPORT's
'---------------------------------------------------------------------------------------
CONST filename$ = "GUI/bacongui.bac"
DECLARE mem$, free$, open$, close$, subfunc$, import$ ASSOC STRING
' ----------------------
' Phase 1: collect info
' ----------------------
OPEN filename$ FOR READING AS myfile
line = 1
WHILE NOT(ENDFILE(myfile))
READLN txt$ FROM myfile
data$ = CHOP$(txt$)
IF REGEX(data$, "=[ \\t]*MEMORY[ \\t]*\\(") THEN mem$(STR$(line)) = CHOP$(LEFT$(data$, INSTR(data$, "=")-1))
IF REGEX(data$, "FREE[ \\t]+") THEN free$(STR$(line)) = CHOP$(MID$(data$, INSTR(data$, "FREE ")+5))
IF REGEX(data$, "OPEN.+AS[ \\t]+") THEN open$(STR$(line)) = CHOP$(MID$(data$, INSTR(data$, "AS ")+3))
IF REGEX(data$, "CLOSE[ \\t]+(FILE|DIRECTORY|MEMORY|NETWORK)[ \\t]+") THEN close$(STR$(line)) = CHOP$(MID$(data$, INSTR(data$, "CLOSE ")+6))
IF REGEX(data$, "^(SUB|FUNCTION)[ \\t]+[a-zA-Z_]+") THEN subfunc$(STR$(line)) = CHOP$( EXTRACT$(MID$(data$, INSTR(data$, " ")+1), "\\(.*", TRUE) )
IF REGEX(data$, "^IMPORT.+FROM.+TYPE") THEN
data$ = MID$(data$, INSTR(data$, CHR$(34))+1)
import$(STR$(line)) = CHOP$(EXTRACT$(data$, "\\(.*|" & CHR$(34) & ".*", TRUE))
ENDIF
INCR line
WEND
CLOSE FILE myfile
' -----------------------------------
' Phase 2: analyze MEMORY/FREE pairs
' -----------------------------------
PRINT "MEMORY/FREE pair checking... ";
LOOKUP mem$ TO line_1$ SIZE size1
LOOKUP free$ TO line_2$ SIZE size2
FOR x = 0 TO size1-1
found = FALSE
FOR y = 0 TO size2-1
IF INSTR(free$(line_2$[y]), mem$(line_1$[x])) THEN
found = TRUE
free$(line_2$[y]) = EXTRACT$(free$(line_2$[y]), mem$(line_1$[x]))
BREAK
FI
NEXT
IF NOT(found) THEN PRINT "MEMORY variable '", mem$(line_1$[x]), "' at line ", line_1$[x], " has no FREE."
NEXT
PRINT "done."
' -----------------------------------
' Analyze OPEN/CLOSE pairs
' -----------------------------------
PRINT "OPEN/CLOSE pair checking... ";
LOOKUP open$ TO line_3$ SIZE size3
LOOKUP close$ TO line_4$ SIZE size4
FOR x = 0 TO size3-1
found = FALSE
FOR y = 0 TO size4-1
IF INSTR(close$(line_4$[y]), open$(line_3$[x])) THEN
found = TRUE
close$(line_4$[y]) = EXTRACT$(close$(line_4$[y]), open$(line_3$[x]))
BREAK
FI
NEXT
IF NOT(found) THEN PRINT "OPEN variable '", open$(line_3$[x]), "' at line ", line_3$[x], " has no CLOSE."
NEXT
PRINT "done."
' ------------------------------------------------------------
' Analyze SUBS and FUNCTIONS to see if they are actually used
' ------------------------------------------------------------
PRINT "Redundant SUB/FUNCTION checking... ";
LOOKUP subfunc$ TO line_5$ SIZE size5
OPEN filename$ FOR READING AS myfile
line = 1
WHILE NOT(ENDFILE(myfile))
READLN txt$ FROM myfile
' Subs and functions
FOR x = 0 TO size5-1
IF VAL(line_5$[x]) = line THEN BREAK
IF INSTR(txt$, subfunc$(line_5$[x])) THEN FREE subfunc$(line_5$[x])
NEXT
INCR line
WEND
CLOSE FILE myfile
FOR x = 0 TO size5-1
IF LEN(subfunc$(line_5$[x])) THEN PRINT "The SUB/FUNC '", subfunc$(line_5$[x]), "' at line ", line_5$[x], " is not used in the program."
NEXT
PRINT "done."
' --------------------------------------------------------------------------------
' Analyze IMPORTS to see if there are no duplicates and if they are actually used
' --------------------------------------------------------------------------------
PRINT "Duplicate IMPORT checking... ";
LOOKUP import$ TO line_6$ SIZE size6
' Duplicates
FOR x = 0 TO size6-1
FOR y = x+1 TO size6-1
IF import$(line_6$[x]) = import$(line_6$[y]) THEN PRINT "Duplicate IMPORT at line ", line_6$[x], " and ", line_6$[y], "."
NEXT
NEXT
PRINT "done."
PRINT "Redundant IMPORT checking... ";
OPEN filename$ FOR READING AS myfile
line = 1
WHILE NOT(ENDFILE(myfile))
READLN txt$ FROM myfile
' Redundant imports
FOR x = 0 TO size6-1
IF VAL(line_6$[x]) = line THEN BREAK
IF INSTR(txt$, import$(line_6$[x])) THEN FREE import$(line_6$[x])
NEXT
INCR line
WEND
CLOSE FILE myfile
FOR x = 0 TO size6-1
IF LEN(import$(line_6$[x])) THEN PRINT "The IMPORT '", import$(line_6$[x]), "' at line ", line_6$[x], " is not used in the program."
NEXT
PRINT "done."
Generated by GNU Enscript 1.6.5.90.