错误报告模块作用:记录并报告编译过程中出现的错误和警告

/*************************************************
 *                                               *
 *  Module: errors.c                             *
 *  Description:                                 *
 *      Errors reporting module. This module     *
 *      collects error/warning messages in a     *
 *      list, marking them with the line number  *
 *      on which they occurred. They can then    *
 *      be sorted and printed as a batch.        *
 *  Author: Van Oostenrijk, A.C.                 *
 *  Modifications:                               *
 *                                               *
 *************************************************
 *                                               *
 *   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.                              *
 *                                               *
 ************************************************
*/

/* printf, NULL */
#include 
<stdio.h>
/* malloc, free */
#include 
<stdlib.h>
/* assert macro */
#include 
<assert.h>
/* General macros. */
#include 
"defs.h"
/* Include linked list interface. */
#include 
"list.h"


//所有的错误信息都记录在一个链表中

/*************************************************
 *                                               *
 *  MACROS                                       *
 *                                               *
 ************************************************
*/

/*
 * Define the character used to terminate messages. Can be
 * the empty string.
 
*/
#define MESSAGEDOT "."

/*************************************************
 *                                               *
 *  TYPES                                        *
 *                                               *
 ************************************************
*/

/*
 *  This structure holds a single error/warning
 *  message (a string) and the line number on which
 *  it occurred.
 
*/
typedef 
struct
{
    
int lineno;
    
char *text;
} ReportEntry;

/*************************************************
 *                                               *
 *  GLOBALS                                      *
 *                                               *
 ************************************************
*/
//错误和警告计数器
static int numErrors = 0, numWarnings = 0;
//指向记录警告信息和错误信息的链表表头, 貌似以前有人说数据结构没有用的?
static List *report = NULL;


/*************************************************
 *                                               *
 *  FUNCTION DEFNIITIONS                         *
 *                                               *
 ************************************************
*/

/*
 *  Free specified instance of the ReportEntry
 *  structure. This callback function is used
 *  by [report], the list of Report Entries.
 
*/
 
//释放链表中entry指向的节点
static BOOL DeleteReportEntry( void *entry )
{
    free( ( (ReportEntry 
*) entry)->text ); //释放text的空间
    free( entry );  //释放ReportEntry结构体的空间
    return( TRUE );
}

/*
 * Add a ReportEntry to the report, with the
 * specified [prefix] ("error" or "warning"),
 * the message [message] and the line number
 * [lineno]. Include the character position
 * [charpos] if it is not -1.
 
*/
 
//在链表尾部增加一条节点,用于记录警告或者错误信息
static void AddText( char *prefix, char *message, int lineno, int charpos )
{
    ReportEntry 
*entry;

    assert( prefix 
!= NULL );
    assert( message 
!= NULL );

    entry 
= (ReportEntry*) malloc( sizeof( ReportEntry ) );
    
//多分配了40个字节用于记录错误或者警告的行号和列号, "error" "warning"前缀和点等
    entry->text = (char*) malloc( strlen(message) + 40 );

    
if( charpos == -1 ) //如果到了文件尾部,没有出错的charpos
    {
        sprintf( entry
->text, "%d - %s: %s%s", lineno, prefix,
            message, MESSAGEDOT );
        
/* DEBUG( "%d - %s: %s%s\n", lineno, prefix,
            message, MESSAGEDOT ); 
*/
    }
    
else
    {
        sprintf( entry
->text, "%d:%d - %s: %s%s", lineno,
            charpos, prefix, message, MESSAGEDOT );
        
/* DEBUG( "%d:%d - %s: %s%s\n", lineno,
            charpos, prefix, message, MESSAGEDOT ); 
*/
    }

    entry
->lineno = lineno;
    ListAppend( report, entry );    
//添加到链表尾部
}

//添加错误信息,包括列号
void AddPosError( char *message, int lineno, int charpos )
{
    numErrors
++;
    AddText( 
"error", message, lineno, charpos );
}

//添加错误信息,不包括列号
void AddError( char *message, int lineno )
{
    numErrors
++;
    AddText( 
"error", message, lineno, -1 );
}

//添加警告信息,包括列号
void AddPosWarning( char *message, int lineno, int charpos )
{
    numWarnings
++;
    AddText( 
"warning", message, lineno, charpos );
}

//添加警告信息,不包括列号
void AddWarning( char *message, int lineno )
{
    numWarnings
++;
    AddText( 
"warning", message, lineno, -1 );
}

//返回错误总数
int GetErrorCount()
{
    
return( numErrors );
}

//返回警告总数
int GetWarningCount()
{
    
return( numWarnings );
}

//初始化链表
void InitializeReport()
{
    numErrors 
= 0;
    numWarnings 
= 0;

    
if( report != NULL )    //链表非空
    {
        ListPurge( report, DeleteReportEntry );
    }
    report 
= ListInit( DeleteReportEntry ); //注册DeleteReportEntry为释放节点空间的函数
}

//将一个无序(对行号而言)的链表删除,并以该链表中的节点重新建立一个有序的链表
void PrintReport()
{
    List 
*sortedReport;
    
int lowestLine;
    
int targetEntry;
    
int i, lineno;
    
void *entry;
    ListNode 
*node;

    sortedReport 
= ListInit( DeleteReportEntry );

    
/*
     * Remove entries from report and put them
     * in sortedReport (sorted).
     
*/
    
while( ListSize( report ) > 0 ) //report链表还不为空
    {
        lowestLine 
= 1 << 30;   //错误或警告信息的最小的行号
        targetEntry = -1;   //最小的行号在链表中的index

        
/* Find lowest line number */
        ListFirst( report );
        
for( i = 0; i < ListSize( report ); i++ )
        {
            lineno 
= ( ( ReportEntry* ) ListGet( report ) )->lineno;
            
if( lineno < lowestLine )
            {
                targetEntry 
= i;
                lowestLine 
= lineno;
            }
            ListNext( report ); 
//指向下一个节点
        }

        
/* Go to lowest entry. */
        ListFirst( report );
        
for( i = 0; i < targetEntry; i++ )
        {
            ListNext( report );
        }

        
/* Remove entry from report, add to sortedReport */
        entry 
= ListGet( report );
        ListUnlink( report );
        ListAppend( sortedReport, entry );  
//添加到有序链表中
    }
    ListPurge( report, DeleteReportEntry );

    
/* Print sortedReport. */
    node 
= ListFirstEx( sortedReport ); //获取指向第一个节点的指针
    while( node != NULL )
    {   
//报告错误或警告信息
        fprintf( stderr, "%s\n", ((ReportEntry*)node->data)->text );
        node 
= ListNextEx( node );  //下一个节点
    }

    
/* Throw away list and contents. */
    
//不需要该有序链表了,删除之
    ListPurge( sortedReport, DeleteReportEntry );

    
//输出错误总数和警告总数
    fprintf( stdout, "%d errors, %d warnings.\n", GetErrorCount(), GetWarningCount() );
}