3
0
mirror of https://github.com/pragma-/pbot.git synced 2024-11-30 07:59:42 +01:00

CGrammar: Fix preprocessor and improve for-loops

This commit is contained in:
Pragmatic Software 2014-06-10 06:05:14 +00:00
parent 9992119b11
commit c4fd8a964f
2 changed files with 86 additions and 65 deletions

View File

@ -13,7 +13,7 @@ use warnings;
# These are set automatically by the build/commit script # These are set automatically by the build/commit script
use constant { use constant {
BUILD_NAME => "PBot", BUILD_NAME => "PBot",
BUILD_REVISION => 623, BUILD_REVISION => 624,
BUILD_DATE => "2014-06-09", BUILD_DATE => "2014-06-09",
}; };

View File

@ -5,12 +5,9 @@
# todo: # todo:
# 1. the entire syntax for pointers to functions. # 1. the entire syntax for pointers to functions.
# 2. preprocessor directives. (getting there) # 2. preprocessor directives. (getting there)
# So, the problem with handling CPP directives is when they
# interrupt something. I'm open to ideas.
# 4. functions to handle the nesting levels (ordinal number generator and CPP stack) # 4. functions to handle the nesting levels (ordinal number generator and CPP stack)
# 6. change returns to prints where appropriate. # 6. change returns to prints where appropriate.
# 7. syntax for int *p[10] vs int (*p)[10] vs int *(*p)[10] # 7. syntax for int *p[10] vs int (*p)[10] vs int *(*p)[10]
# etc
{ {
my @defined_types = ('`FILE`'); my @defined_types = ('`FILE`');
@ -27,7 +24,7 @@ startrule:
} }
startrule(?) startrule(?)
translation_unit: translation_unit:
(comment (comment
| external_declaration | external_declaration
| function_definition | function_definition
@ -35,9 +32,9 @@ translation_unit:
| preproc[matchrule => 'translation_unit']) | preproc[matchrule => 'translation_unit'])
preproc: preproc:
<skip: '[ \t]*'> definition definition
| undefinition | undefinition
| <skip: '[ \t]*'> inclusion | inclusion
| line | line
| error | error
| pragma | pragma
@ -45,41 +42,44 @@ preproc:
{ $return = $item[-1]; } { $return = $item[-1]; }
definition: definition:
<skip: '[ \t]*'> /\n*/ macro_definition macro_definition
| <skip: '[ \t]*'> /\s*?\n*#/ 'define' identifier token_sequence(?) .../\s*?\n/ | '#' 'define' identifier token_sequence(?) <skip: '[ \t]*'> "\n"
{ {
my $token_sequence = join('',@{$item{'token_sequence(?)'}}); my $token_sequence = join('',@{$item{'token_sequence(?)'}});
$return = "Define $item{identifier}"; $return = "Define the macro $item{identifier}";
$return .= " to mean $token_sequence" if $token_sequence; $return .= " to mean $token_sequence" if $token_sequence;
$return .= ".\n"; $return .= ".\n";
} }
macro_definition: macro_definition:
'#' 'define' identifier '(' <leftop: identifier ',' identifier > ')' token_sequence "\n" '#' 'define' identifier '(' <leftop: identifier ',' identifier> ')' token_sequence <skip: '[ \t]*'> "\n"
{ {
my @symbols = @{$item[-4]}; my @symbols = @{$item[-5]};
my $last; my $last;
$return = "Define the macro $item[3] "; push @macros, $item{identifier};
push @macros, $item[3]; $return = "Define the macro $item{identifier} ";
if ($#symbols > 0) { if ($#symbols > 0) {
$last = pop @symbols; $last = pop @symbols;
$return .= "with the symbols " . join(", ",@symbols) . " and $last "; $return .= "with the symbols " . join(", ",@symbols) . " and $last ";
} else { } else {
$return .= "with the symbol $symbols[0] "; $return .= "with the symbol $symbols[0] ";
} }
$return .= "to use the token sequence \'$item{token_sequence}\'.\n"; $return .= "to use the token sequence `$item{token_sequence}`.\n";
} }
undefinition: undefinition:
<skip: '[ \t]*'> ("\n")(s?) '#' 'undef' identifier '#' 'undef' identifier <skip: '[ \t]*'> "\n"
{ $return = "\nAnnul the definition of $item{identifier}.\n"; } {
@macros = grep { $_ ne $item{identifier} } @macros;
$return = "\nAnnul the definition of $item{identifier}.\n";
}
inclusion: inclusion:
<skip: '[ \t]*'> /\s*?\n*#/ 'include' '<' filename '>' .../\s*?\n/ '#' 'include' '<' filename '>' <skip: '[ \t]*'> "\n"
{ $return = "\nInclude system file $item{filename}.\n"; } { $return = "\nInclude system file $item{filename}.\n"; }
| <skip: '[ \t]*'> /\s*?\n*#/ 'include' '"' filename '"' .../\s*?\n/ | '#' 'include' '"' filename '"' <skip: '[ \t]*'> "\n"
{ $return = "\nInclude user file $item{filename}.\n"; } { $return = "\nInclude user file $item{filename}.\n"; }
| <skip: '[ \t]*'> /\s*?\n*#/ 'include' token | '#' 'include' token
{ $return = "\nImport code noted by the token $item{token}.\n"; } { $return = "\nImport code noted by the token $item{token}.\n"; }
filename: filename:
@ -88,48 +88,44 @@ filename:
line: line:
'#' 'line' constant ('"' filename '"' '#' 'line' constant ('"' filename '"'
{ $return = "and filename $item{filename}"; } { $return = "and filename $item{filename}"; }
)(?) /\n+/ )(?) <skip: '[ \t]*'> "\n"
{ $return = "\nThis is line number $item{constant}" . join('', @{$item[-1]}) . ".\n"; } { $return = "\nThis is line number $item{constant} " . join('', @{$item[-3]}) . ".\n"; }
error: error:
'#' 'error' token_sequence(?) '#' 'error' token_sequence(?) <skip: '[ \t]*'> "\n"
{ $return = "Stop compilation with error \"" . join('', @{$item{'token_sequence(?)'}}) . "\".\n"; } { $return = "Stop compilation with error \"" . join('', @{$item{'token_sequence(?)'}}) . "\".\n"; }
pragma: pragma:
'#' 'pragma' token_sequence(?) '#' 'pragma' token_sequence(?) <skip: '[ \t]*'> "\n"
{ {
my $pragma = join('',@{$item[-1]}); my $pragma = join('',@{$item{'token_sequence(?)'}});
if ($pragma) { $pragma = ' "' . $pragma . '"'; } if ($pragma) { $pragma = ' "' . $pragma . '"'; }
$return = "\nNote: a compiler-dependent pragma$pragma is added here.\n"; $return = "Process a compiler-dependent pragma$pragma.\n";
} }
preproc_conditional: preproc_conditional:
<skip: '[ \t]*'> /\n*/ if_line[matchrule => $arg{matchrule}] if_line[matchrule => $arg{matchrule}]
{ $rule_name = $arg{matchrule}; } { $rule_name = $arg{matchrule}; }
<matchrule: $rule_name>(s?) <matchrule: $rule_name>(s?)
{ $return = $item{if_line} . join('',@{$item[-1]}); } { $return = $item{if_line} . join('',@{$item[-1]}); }
(elif_parts[matchrule => $rule_name])(?) (elif_parts[matchrule => $rule_name])(?)
(else_parts[matchrule => $rule_name])(?) (else_parts[matchrule => $rule_name])(?)
{ $return .= join('',@{$item[-2]}) . join('',@{$item[-1]}); } { $return .= join('',@{$item[-2]}) . join('',@{$item[-1]}); }
/\n*/ '#' 'endif' '#' 'endif'
{ $return .= "\nNote: This ends a conditional inclusion section.\n"; } { $return .= "End preprocessor conditional.\n"; }
if_line: if_line:
<skip: '[ \t]*'> '#' 'ifdef' identifier .../\n+/ '#' 'ifdef' identifier <skip: '[ \t]*'> "\n"
{ {
$return = "\nNote: The current context is interrupted.\n"; $return .= "If the macro $item{identifier} is defined, then ^L";
$return .= "The next section is used only if $item{identifier} is defined.\n";
} }
| <skip: '[ \t]*'> '#' 'ifndef' identifier /\n+/ | '#' 'ifndef' identifier /\n+/
{ {
$return = "\nNote: The current context is interrupted.\n"; $return .= "If the macro $item{identifier} is not defined, then ^L";
$return .= "The next section is used only if $item{identifier} is NOT defined.\n";
} }
| <skip: '[ \t]*'> '#' 'if' constant_expression "\n" | '#' 'if' constant_expression "\n"
{ {
$return = "\nNote: The current context is interrupted.\n"; $return .= "If the preprocessor condition^L $item{constant_expression} is true, then ^L";
$return .= "The next section is used only if we meet this macro condition:\n";
$return .= "\"$item{constant_expression}\".\n";
} }
elif_parts: elif_parts:
@ -149,7 +145,7 @@ else_parts:
{ $rule_name = $arg{matchrule}; } { $rule_name = $arg{matchrule}; }
(<matchrule: $rule_name>)[matchrule => $arg{matchrule}](s?) (<matchrule: $rule_name>)[matchrule => $arg{matchrule}](s?)
{ {
$return = "\nNote: we interrupt the current context once more.\n" . "The following section gets included if the previous precondition fails.\n"; $return = "Otherwise, ^L";
$return .= join('',@{$item[-1]}); $return .= join('',@{$item[-1]});
} }
@ -195,7 +191,7 @@ function_definition:
$return .= " taking $parameter_list"; $return .= " taking $parameter_list";
} }
$return .= " and returning $return_type.\nTo perform the function: ^L"; $return .= " and returning $return_type.\nTo perform the function, ^L";
if ($declaration_list) { if ($declaration_list) {
$return .= $declaration_list; $return .= $declaration_list;
@ -203,6 +199,8 @@ function_definition:
if ($statement_list ) { if ($statement_list ) {
$return .= $statement_list; $return .= $statement_list;
} else {
$return .= "Do nothing.\n";
} }
# $return .= "End of function $name.\n"; # $return .= "End of function $name.\n";
@ -290,7 +288,7 @@ statement:
iteration_statement: iteration_statement:
'for' '(' <commit> for_initialization(?) ';' for_expression(?) ';' for_increment(?) ')' 'for' '(' <commit> for_initialization(?) ';' for_expression(?) ';' for_increment(?) ')'
statement[context => 'for loop'] statement[context => 'statement']
{ {
my $initialization = join('', @{$item{'for_initialization(?)'}}); my $initialization = join('', @{$item{'for_initialization(?)'}});
my $item_expression = join('',@{$item{'for_expression(?)'}}); my $item_expression = join('',@{$item{'for_expression(?)'}});
@ -329,7 +327,7 @@ iteration_statement:
{ $return = "Do the following:^L $item{statement}\nDo this as long as $item{expression}.\n"; } { $return = "Do the following:^L $item{statement}\nDo this as long as $item{expression}.\n"; }
for_initialization: for_initialization:
expression[context => 'statement'] expression[context => 'for loop']
for_expression: for_expression:
expression[context => 'for_expression'] expression[context => 'for_expression']
@ -404,7 +402,7 @@ assignment_expression:
my $assignment_expression = $item{assignment_expression}; my $assignment_expression = $item{assignment_expression};
my $assignment_operator = $item{assignment_operator}; my $assignment_operator = $item{assignment_operator};
if ($arg{context} eq 'statement' ) { if ($arg{context} eq 'statement' or $arg{context} eq 'for loop') {
$return .= "${$item{assignment_operator}}[0] $item{unary_expression}${$item{assignment_operator}}[1] $assignment_expression"; $return .= "${$item{assignment_operator}}[0] $item{unary_expression}${$item{assignment_operator}}[1] $assignment_expression";
} else { } else {
$return = "$item{unary_expression}, $assignment_operator $assignment_expression"; $return = "$item{unary_expression}, $assignment_operator $assignment_expression";
@ -425,8 +423,11 @@ conditional_expression:
assignment_operator: assignment_operator:
'=' '='
{ {
print STDERR "arg1: [$arg{context}]\n";
if ($arg{context} eq 'statement') { if ($arg{context} eq 'statement') {
$return = ['Assign to', ' the value' ]; $return = ['Assign to', ' the value' ];
} elsif ($arg{context} eq 'for loop') {
$return = ['assigning to', ' the value' ];
} else { } else {
$return = ', which is assigned to be '; $return = ', which is assigned to be ';
} }
@ -434,7 +435,9 @@ assignment_operator:
| '+=' | '+='
{ {
if ($arg{context} eq 'statement') { if ($arg{context} eq 'statement') {
$return = ['Increment',' by'] $return = ['Increment',' by'];
} elsif ($arg{context} eq 'for loop') {
$return = ['incrementing',' by'];
} else { } else {
$return = 'which is incremented by '; $return = 'which is incremented by ';
} }
@ -443,6 +446,8 @@ assignment_operator:
{ {
if ($arg{context} eq 'statement') { if ($arg{context} eq 'statement') {
$return = ['Decrement' , ' by']; $return = ['Decrement' , ' by'];
} elsif ($arg{context} eq 'for loop') {
$return = ['decrementing' , ' by'];
} else { } else {
$return = 'which is decremented by '; $return = 'which is decremented by ';
} }
@ -450,7 +455,9 @@ assignment_operator:
| '*=' | '*='
{ {
if ($arg{context} eq 'statement') { if ($arg{context} eq 'statement') {
$return = ['Multiply' , ' by'] $return = ['Multiply' , ' by'];
} elsif ($arg{context} eq 'for loop') {
$return = ['multiplying' , ' by'];
} else { } else {
$return = 'which is multiplied by '; $return = 'which is multiplied by ';
} }
@ -459,6 +466,8 @@ assignment_operator:
{ {
if ($arg{context} eq 'statement') { if ($arg{context} eq 'statement') {
$return = ['Divide' , ' by' ]; $return = ['Divide' , ' by' ];
} elsif ($arg{context} eq 'for loop') {
$return = ['dividing' , ' by' ];
} else { } else {
$return = 'which is divided by '; $return = 'which is divided by ';
} }
@ -467,6 +476,8 @@ assignment_operator:
{ {
if ($arg{context} eq 'statement') { if ($arg{context} eq 'statement') {
$return = ['Reduce', ' to modulo '] ; $return = ['Reduce', ' to modulo '] ;
} elsif ($arg{context} eq 'for loop') {
$return = ['reducing', ' to modulo '] ;
} else { } else {
$return = 'which is reduced to modulo '; $return = 'which is reduced to modulo ';
} }
@ -475,6 +486,8 @@ assignment_operator:
{ {
if ($arg{context} eq 'statement') { if ($arg{context} eq 'statement') {
$return = ['Bit-shift', ' left by']; $return = ['Bit-shift', ' left by'];
} elsif ($arg{context} eq 'for loop') {
$return = ['bit-shifting', ' left by'];
} else { } else {
$return = 'which is bit-shifted left by '; $return = 'which is bit-shifted left by ';
} }
@ -483,6 +496,8 @@ assignment_operator:
{ {
if ($arg{context} eq 'statement') { if ($arg{context} eq 'statement') {
$return = ['Bit-shift', ' right by']; $return = ['Bit-shift', ' right by'];
} elsif ($arg{context} eq 'for loop') {
$return = ['bit-shifting', ' right by'];
} else { } else {
$return = 'which is bit-shifted right by '; $return = 'which is bit-shifted right by ';
} }
@ -490,25 +505,31 @@ assignment_operator:
| '&=' | '&='
{ {
if ($arg{context} eq 'statement') { if ($arg{context} eq 'statement') {
$return = ['Bit-wise anded', ' by' ]; $return = ['Bit-wise ANDed', ' by' ];
} elsif ($arg{context} eq 'for loop') {
$return = ['bit-wise ANDing', ' by' ];
} else { } else {
$return = 'which is bit-wise anded by '; $return = 'which is bit-wise ANDed by ';
} }
} }
| '^=' | '^='
{ {
if ($arg{context} eq 'statement') { if ($arg{context} eq 'statement') {
$return = ['Exclusive-or',' by']; $return = ['Exclusive-OR',' by'];
} elsif ($arg{context} eq 'for loop') {
$return = ['exclusive-ORing',' by'];
} else { } else {
$return = 'which is exclusive-orred by '; $return = 'which is exclusive-ORed by ';
} }
} }
| '|=' | '|='
{ {
if ($arg{context} eq 'statement') { if ($arg{context} eq 'statement') {
$return = ['Bit-wise orred', ' by']; $return = ['Bit-wise ORed', ' by'];
} elsif ($arg{context} eq 'for loop') {
$return = ['bit-wise ORing', ' by'];
} else { } else {
$return = 'which is bit-wise orred by '; $return = 'which is bit-wise ORed by ';
} }
} }
@ -529,9 +550,9 @@ logical_OR_AND_expression:
log_OR_AND_bit_or_and_eq: log_OR_AND_bit_or_and_eq:
'||' { $return = ' or '; } '||' { $return = ' or '; }
| '&&' { $return = ' and '; } | '&&' { $return = ' and '; }
| '|' { $return = ' bitwise orred by '; } | '|' { $return = ' bitwise ORed by '; }
| '&' { $return = ' bitwise anded by '; } | '&' { $return = ' bitwise ANDed by '; }
| '^' { $return = ' bitwise xorred by ';} | '^' { $return = ' bitwise XORed by ';}
| '==' { $return = ' is equal to ' ; } | '==' { $return = ' is equal to ' ; }
| '!=' { $return = ' is not equal to ' ; } | '!=' { $return = ' is not equal to ' ; }
@ -591,8 +612,8 @@ cast_expression:
declaration_list: declaration_list:
# <skip: '\s*'> # <skip: '\s*'>
declaration(s) preproc[context => 'statement'](?) declaration(s)
{ $return = join('', @{$item{'declaration(s)'}}); } { $return = join('', @{$item{'preproc(?)'}}) . join('', @{$item{'declaration(s)'}}); }
declaration: declaration:
declaration_specifiers init_declarator_list(?) ';' declaration_specifiers init_declarator_list(?) ';'
@ -781,7 +802,7 @@ postfix_expression:
# To discriminate between macros and functions. # To discriminate between macros and functions.
foreach (@macros) { foreach (@macros) {
if ($basic eq "'$_'") { if ($basic eq $_) {
$return =~ s/Call/Insert/; $return =~ s/Call/Insert/;
$return =~ s/function/macro/; $return =~ s/function/macro/;
} }
@ -839,7 +860,7 @@ postfix_expression:
if ($arg{context} eq 'statement') { if ($arg{context} eq 'statement') {
$return = "increment $basic by one"; $return = "increment $basic by one";
} else { } else {
$return = "$return (which is incremented up by one)"; $return = "$return which is incremented by one";
} }
} }
} }
@ -850,7 +871,7 @@ postfix_expression:
if ($arg{context} eq 'statement') { if ($arg{context} eq 'statement') {
$return = "decrement $basic by one"; $return = "decrement $basic by one";
} else { } else {
$return = "$return (which is decremented by one)"; $return = "$return which is decremented by one";
} }
} }
$basic = pop @basics; $basic = pop @basics;