错误报告模块作用:记录并报告编译过程中出现的错误和警告
/*************************************************
* *
* 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() );
}