ack/lang/cem/cemcom/statement.g

521 lines
7.4 KiB
Plaintext
Raw Permalink Normal View History

/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*/
1994-06-24 14:02:31 +00:00
/* $Id$ */
1986-03-10 13:07:55 +00:00
/* STATEMENT SYNTAX PARSER */
{
#include "lint.h"
#ifndef LINT
#include <em.h>
#else
#include "l_em.h"
#include "l_lint.h"
#endif /* LINT */
1986-03-10 13:07:55 +00:00
#include "debug.h"
#include "botch_free.h"
1991-11-08 15:12:28 +00:00
#include "dbsymtab.h"
1986-03-10 13:07:55 +00:00
#include "arith.h"
#include "LLlex.h"
#include "type.h"
#include "idf.h"
#include "label.h"
#include "expr.h"
#include "code.h"
#include "stack.h"
#include "def.h"
1991-11-08 15:12:28 +00:00
#ifdef DBSYMTAB
#include <stb.h>
#endif /* DBSYMTAB */
1986-03-10 13:07:55 +00:00
extern int level;
1991-11-08 15:12:28 +00:00
extern char options[];
1986-03-10 13:07:55 +00:00
}
1989-03-06 15:17:39 +00:00
/* Each statement construction is stacked in order to trace a ???
1986-03-10 13:07:55 +00:00
statement to such a construction. Example: a case statement should
be recognized as a piece of the most enclosing switch statement.
*/
/* 9 */
statement
1988-08-19 13:55:22 +00:00
{
#ifdef LINT
lint_statement();
#endif /* LINT */
1988-08-19 13:55:22 +00:00
}
1986-03-10 13:07:55 +00:00
:
%if (AHEAD != ':')
1986-03-10 13:07:55 +00:00
expression_statement
|
label ':' statement
|
compound_statement
1986-03-10 13:07:55 +00:00
|
if_statement
|
while_statement
|
do_statement
|
for_statement
|
switch_statement
|
case_statement
|
default_statement
|
1987-03-25 23:14:43 +00:00
BREAK
1988-08-19 13:55:22 +00:00
{
code_break();
#ifdef LINT
lint_break_stmt();
#endif /* LINT */
1988-08-19 13:55:22 +00:00
}
1987-03-25 23:14:43 +00:00
';'
1986-03-10 13:07:55 +00:00
|
1987-03-25 23:14:43 +00:00
CONTINUE
1988-08-19 13:55:22 +00:00
{
code_continue();
#ifdef LINT
lint_continue_stmt();
#endif /* LINT */
1988-08-19 13:55:22 +00:00
}
1987-03-25 23:14:43 +00:00
';'
1986-03-10 13:07:55 +00:00
|
return_statement
|
jump
|
';'
|
asm_statement
;
1988-09-16 23:19:50 +00:00
1986-03-10 13:07:55 +00:00
expression_statement
{ struct expr *expr;
}
:
expression(&expr)
';'
{
#ifdef DEBUG
1988-09-16 23:19:50 +00:00
print_expr("expression_statement", expr);
#endif /* DEBUG */
1986-03-10 13:07:55 +00:00
code_expr(expr, RVAL, FALSE, NO_LABEL, NO_LABEL);
free_expression(expr);
}
;
label
{ struct idf *idf;
}
:
identifier(&idf)
{
/* This allows the following absurd case:
typedef int grz;
main() {
grz: printf("A labelled statement\n");
}
*/
#ifdef LINT
lint_label();
#endif /* LINT */
1986-03-10 13:07:55 +00:00
define_label(idf);
C_df_ilb((label)idf->id_def->df_address);
1986-03-10 13:07:55 +00:00
}
;
if_statement
{
struct expr *expr;
label l_true = text_label();
label l_false = text_label();
label l_end = text_label();
}
:
IF
'('
expression(&expr)
{
opnd2test(&expr, IF);
if (is_cp_cst(expr)) {
/* The comparison has been optimized
to a 0 or 1.
1986-03-10 13:07:55 +00:00
*/
if (expr->VL_VALUE == (arith)0) {
C_bra(l_false);
}
/* else fall through */
1988-09-25 17:29:37 +00:00
#ifdef LINT
start_if_part(1);
#endif /* LINT */
}
else {
code_expr(expr, RVAL, TRUE, l_true, l_false);
C_df_ilb(l_true);
#ifdef LINT
1988-09-25 17:29:37 +00:00
start_if_part(0);
#endif /* LINT */
1988-09-25 17:29:37 +00:00
}
free_expression(expr);
1986-03-10 13:07:55 +00:00
}
')'
statement
[%prefer
ELSE
{
#ifdef LINT
start_else_part();
#endif /* LINT */
1986-03-10 13:07:55 +00:00
C_bra(l_end);
C_df_ilb(l_false);
1986-03-10 13:07:55 +00:00
}
statement
{ C_df_ilb(l_end);
#ifdef LINT
end_if_else_stmt();
#endif /* LINT */
1986-03-10 13:07:55 +00:00
}
|
empty
{ C_df_ilb(l_false);
#ifdef LINT
end_if_stmt();
#endif /* LINT */
1986-03-10 13:07:55 +00:00
}
]
;
while_statement
{
struct expr *expr;
label l_break = text_label();
label l_continue = text_label();
label l_body = text_label();
}
:
WHILE
{
stack_stmt(l_break, l_continue);
C_df_ilb(l_continue);
1986-03-10 13:07:55 +00:00
}
'('
expression(&expr)
{
opnd2test(&expr, WHILE);
if (is_cp_cst(expr)) {
1986-03-10 13:07:55 +00:00
if (expr->VL_VALUE == (arith)0) {
C_bra(l_break);
}
}
else {
code_expr(expr, RVAL, TRUE, l_body, l_break);
C_df_ilb(l_body);
1989-03-06 15:17:39 +00:00
}
#ifdef LINT
1989-03-06 15:17:39 +00:00
start_while_stmt(expr);
#endif /* LINT */
1989-03-06 15:17:39 +00:00
1986-03-10 13:07:55 +00:00
}
')'
statement
{
C_bra(l_continue);
C_df_ilb(l_break);
unstack_stmt();
1986-03-10 13:07:55 +00:00
free_expression(expr);
#ifdef LINT
1989-03-06 15:17:39 +00:00
end_loop_body();
end_loop_stmt();
#endif /* LINT */
1986-03-10 13:07:55 +00:00
}
;
do_statement
{ struct expr *expr;
label l_break = text_label();
label l_continue = text_label();
label l_body = text_label();
}
:
DO
{ C_df_ilb(l_body);
stack_stmt(l_break, l_continue);
#ifdef LINT
1989-03-06 15:17:39 +00:00
start_do_stmt();
#endif /* LINT */
1986-03-10 13:07:55 +00:00
}
statement
WHILE
'('
1989-03-06 15:17:39 +00:00
{
#ifdef LINT
end_loop_body();
#endif /* LINT */
1989-03-06 15:17:39 +00:00
C_df_ilb(l_continue);
1986-03-10 13:07:55 +00:00
}
expression(&expr)
{
opnd2test(&expr, WHILE);
if (is_cp_cst(expr)) {
1986-03-10 13:07:55 +00:00
if (expr->VL_VALUE == (arith)1) {
C_bra(l_body);
}
#ifdef LINT
end_do_stmt(1, expr->VL_VALUE != (arith)0);
#endif /* LINT */
1986-03-10 13:07:55 +00:00
}
else {
code_expr(expr, RVAL, TRUE, l_body, l_break);
#ifdef LINT
end_do_stmt(0, 0);
#endif /* LINT */
}
C_df_ilb(l_break);
1986-03-10 13:07:55 +00:00
}
')'
';'
{
unstack_stmt();
1986-03-10 13:07:55 +00:00
free_expression(expr);
}
;
for_statement
{ struct expr *e_init = 0, *e_test = 0, *e_incr = 0;
label l_break = text_label();
label l_continue = text_label();
label l_body = text_label();
label l_test = text_label();
}
:
FOR
{ stack_stmt(l_break, l_continue);
1986-03-10 13:07:55 +00:00
}
'('
[
expression(&e_init)
{ code_expr(e_init, RVAL, FALSE, NO_LABEL, NO_LABEL);
}
]?
';'
{ C_df_ilb(l_test);
1986-03-10 13:07:55 +00:00
}
[
expression(&e_test)
{
opnd2test(&e_test, FOR);
if (is_cp_cst(e_test)) {
1986-03-10 13:07:55 +00:00
if (e_test->VL_VALUE == (arith)0) {
C_bra(l_break);
}
}
else {
code_expr(e_test, RVAL, TRUE, l_body, l_break);
C_df_ilb(l_body);
}
1986-03-10 13:07:55 +00:00
}
]?
';'
expression(&e_incr)?
')'
1988-09-16 23:19:50 +00:00
{
#ifdef LINT
1989-03-06 15:17:39 +00:00
start_for_stmt(e_test);
#endif /* LINT */
1988-09-16 23:19:50 +00:00
}
1986-03-10 13:07:55 +00:00
statement
{
#ifdef LINT
1989-03-06 15:17:39 +00:00
end_loop_body();
#endif /* LINT */
C_df_ilb(l_continue);
1986-03-10 13:07:55 +00:00
if (e_incr)
1986-03-17 17:47:04 +00:00
code_expr(e_incr, RVAL, FALSE,
NO_LABEL, NO_LABEL);
1986-03-10 13:07:55 +00:00
C_bra(l_test);
C_df_ilb(l_break);
unstack_stmt();
1986-03-10 13:07:55 +00:00
free_expression(e_init);
free_expression(e_test);
free_expression(e_incr);
1989-03-06 15:17:39 +00:00
#ifdef LINT
end_loop_stmt();
#endif /* LINT */
1986-03-10 13:07:55 +00:00
}
;
switch_statement
{
struct expr *expr;
}
:
SWITCH
'('
expression(&expr)
1986-03-10 13:07:55 +00:00
{
code_startswitch(&expr);
#ifdef LINT
start_switch_part(is_cp_cst(expr));
#endif /* LINT */
1986-03-10 13:07:55 +00:00
}
')'
statement
{
#ifdef LINT
end_switch_stmt();
#endif /* LINT */
1986-03-10 13:07:55 +00:00
code_endswitch();
free_expression(expr);
}
;
case_statement
{
struct expr *expr;
}
:
CASE
constant_expression(&expr)
{
#ifdef LINT
lint_case_stmt(0);
#endif /* LINT */
code_case(expr);
1986-03-10 13:07:55 +00:00
free_expression(expr);
}
':'
statement
;
default_statement
:
DEFAULT
{
#ifdef LINT
lint_case_stmt(1);
#endif /* LINT */
1986-03-10 13:07:55 +00:00
code_default();
}
':'
statement
;
return_statement
{ struct expr *expr = 0;
}
:
RETURN
[
expression(&expr)
{
#ifdef LINT
lint_ret_conv(expr);
#endif /* LINT */
1986-03-10 13:07:55 +00:00
do_return_expr(expr);
free_expression(expr);
#ifdef LINT
1989-03-06 15:17:39 +00:00
lint_return_stmt(VALRETURNED);
#endif /* LINT */
1986-03-10 13:07:55 +00:00
}
|
empty
{
do_return();
#ifdef LINT
1989-03-06 15:17:39 +00:00
lint_return_stmt(NOVALRETURNED);
#endif /* LINT */
1986-03-10 13:07:55 +00:00
}
]
';'
;
jump
{ struct idf *idf;
}
:
GOTO
identifier(&idf)
';'
{
apply_label(idf);
C_bra((label)idf->id_def->df_address);
#ifdef LINT
lint_jump_stmt(idf);
#endif /* LINT */
1986-03-10 13:07:55 +00:00
}
;
1991-11-08 15:12:28 +00:00
compound_statement
{
#ifdef DBSYMTAB
static int brc_level = 1;
int decl_seen = brc_level == 1;
#endif /* DBSYMTAB */
}
:
1986-03-10 13:07:55 +00:00
'{'
{
stack_level();
}
[%while ((DOT != IDENTIFIER && AHEAD != ':') ||
(DOT == IDENTIFIER && AHEAD == IDENTIFIER))
/* >>> conflict on TYPE_IDENTIFIER, IDENTIFIER */
1986-03-10 13:07:55 +00:00
declaration
1991-11-08 15:12:28 +00:00
{
#ifdef DBSYMTAB
decl_seen++;
#endif /* DBSYMTAB */
}
1986-03-10 13:07:55 +00:00
]*
1991-11-08 15:12:28 +00:00
{
#ifdef DBSYMTAB
++brc_level;
if (options['g'] && decl_seen) {
C_ms_std((char *) 0, N_LBRAC, brc_level);
}
#endif /* DBSYMTAB */
}
1986-03-10 13:07:55 +00:00
[%persistent
statement
]*
'}'
{
unstack_level();
1991-11-08 15:12:28 +00:00
#ifdef DBSYMTAB
if (options['g'] && decl_seen) {
C_ms_std((char *) 0, N_RBRAC, brc_level);
}
brc_level--;
#endif /* DBSYMTAB */
1986-03-10 13:07:55 +00:00
}
;
asm_statement
{ char *asm_bts;
int asm_len;
1986-03-10 13:07:55 +00:00
}
:
ASM
'('
STRING
{ asm_bts = dot.tk_bts;
asm_len = dot.tk_len;
1986-03-10 13:07:55 +00:00
}
')'
';'
{ code_asm(asm_bts, asm_len);
1986-03-10 13:07:55 +00:00
}
;
1988-08-19 13:55:22 +00:00