Skip to content

Instantly share code, notes, and snippets.

@Chubek
Last active January 15, 2024 14:37
Show Gist options
  • Save Chubek/db1e1084ce4439ba40eb8f758b774b46 to your computer and use it in GitHub Desktop.
Save Chubek/db1e1084ce4439ba40eb8f758b774b46 to your computer and use it in GitHub Desktop.
ErrorPP.pl: A C preprocessor which adds error and warning functions

ErrorPP.pl is a preprocessor DSL that targets C. Basically, it adds two extra directives to the C preprocessor:

#error-decl f::<error function name> m::"<error function message>" c::<exit code>
#warning-decl f::<wraning function name> m::"<warning function message>" 

You may add several of these directives inside the same file. You then can call this functions (they accept no arguments) and the error/warning will be invoked.

Note: If you wish to know more, use the POD documentation inside the script, using tools like Pod2Man.

This DSL is very similar to the other Perl script I wrote today, AllocPP:

https://gist.github.com/Chubek/b2846855e5bb71a67c7e3effc6beefd6

Thanks, Chubak

#!/usr/bin/perl
use strict;
use warnings;
use Getopt::Std;
my %opts;
getopts('i:o:', \%opts);
my $input_fh = \*STDIN;
my $output_fh = \*STDOUT;
if (defined $opts{i}) {
open($input_fh, '<', $opts{i}) or die "Cannot open input file $opts{i}: $!\n";
}
if (defined $opts{o}) {
open($output_fh, '>', $opts{o}) or die "Cannot open output file $opts{o}: $!\n";
}
=head1 NAME
ErrorPP.pl - Generate error and warning functions based on DSL directives
=head1 SYNOPSIS
ErrorPP.pl [-i input_file] [-o output_file]
=head1 DESCRIPTION
This script reads DSL (Domain-Specific Language) directives from the input file or
standard input and generates error and warning functions based on the provided directives.
The DSL supports two types of directives: '#error-decl' and '#warning-decl'. The generated
functions have colorful output for errors and warnings using ANSI escape codes.
=head1 DSL DIRECTIVES
=over 4
=item B<#error-decl>
#error-decl f::function_name, m::"Error message", c::exit_code
Declares an error function with the specified name, error message, and optional exit code.
=item B<#warning-decl>
#warning-decl f::function_name, m::"Warning message"
Declares a warning function with the specified name and warning message.
=back
=head1 GENERATED FUNCTIONS
The script generates the following types of functions:
=over 4
=item B<Error Functions>
void function_name();
Generates error functions with colorful output for error messages. The function exits
with the specified exit code if provided.
=item B<Warning Functions>
void function_name();
Generates warning functions with colorful output for warning messages.
=back
=head1 EXAMPLE
#error-decl f::"file_open_error", m::"Error occurred because of IO", c::22
#warning-decl f::"reallocation_warning", m::"This reallocation may be wrong"
int main() {
// Your code here
// Generating errors and warnings
file_open_error();
reallocation_warning();
return 0;
}
=head1 AUTHOR
Chubak Bidpaa
=head1 COPYRIGHT
NU GENERAL PUBLIC LICENSE
Version 3, June 2007
Preamble:
The GNU General Public License is a free, copyleft license for software and other kinds of works.
Terms and Conditions:
- You are free to run, modify, and distribute the software.
- Source code access is required for any distributed modifications.
- Derivative works must be distributed under the GPL.
Additional Permissions:
- Propagation of covered works is permitted without modification.
- Adding exceptions to this license is allowed.
Disclaimer of Warranty:
The software is provided without any warranty.
Full License Text:
The complete text of the GNU General Public License version 3.0 can be found at [GNU GPL v3.0](https://www.gnu.org/licenses/gpl-3.0.en.html).
=back
=cut
my @error_decls;
my @warning_decls;
my @bypasses;
my @declarations;
my @error_definitions;
my @warning_definitions;
while (<$input_fh>) {
if (/^#error-decl\s+f::([A-Za-z_][A-Za-z0-9_]*)\s*,\s*m::"(.*)"\s*,\s*c::([0-9]+)\s*$/) {
push @error_decls, {
func_name => $1,
message => $2,
exit_code => $3 + 0,
};
} elsif (/^#warning-decl\s+f::([A-Za-z_][A-Za-z0-9_]*)\s*,\s*m::"(.*)"\s*$/) {
push @warning_decls, {
func_name => $1,
message => $2,
};
} else {
push @bypasses, $_;
}
}
sub generate_declarations {
my ($decls) = @_;
foreach my $decl (@$decls) {
push @declarations, "void $decl->{func_name}(void);";
}
}
sub generate_error_functions {
my ($errors) = @_;
foreach my $error (@$errors) {
push @error_definitions, <<"END_ERROR";
void $error->{func_name}() {
fprintf(stderr, "\\e[1;31mError:\\e[0m $error->{message}\\n");
exit($error->{exit_code});
}
END_ERROR
}
}
sub generate_warning_functions {
my ($warnings) = @_;
foreach my $warning (@$warnings) {
push @warning_definitions, <<"END_WARNING";
void $warning->{func_name}() {
fprintf(stderr, "\\e[1;33mWarning:\\e[0m $warning->{message}\\n");
}
END_WARNING
}
}
generate_declarations(\@error_decls);
generate_declarations(\@warning_decls);
generate_error_functions(\@error_decls);
generate_warning_functions(\@warning_decls);
print $output_fh "\n", join("\n\n", @declarations), "\n\n";
print $output_fh "\n", join("", @bypasses), "\n\n";
print $output_fh "\n", join("\n\n", @error_definitions), "\n\n";
print $output_fh "\n", join("\n\n", @warning_definitions), "\n\n";
# Close files if not STDIN or STDOUT
close($input_fh) if defined $opts{i};
close($output_fh) if defined $opts{o};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment