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.