1988-10-26 15:21:11 +00:00
|
|
|
/* R E A D ( L N ) & W R I T E ( L N ) */
|
|
|
|
|
2013-05-14 19:47:04 +00:00
|
|
|
#include "parameters.h"
|
1988-10-26 15:21:11 +00:00
|
|
|
#include "debug.h"
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
#include <em.h>
|
|
|
|
|
2019-02-23 17:15:23 +00:00
|
|
|
#include "print.h"
|
1988-10-26 15:21:11 +00:00
|
|
|
#include "LLlex.h"
|
|
|
|
#include "def.h"
|
|
|
|
#include "main.h"
|
1989-05-03 10:30:22 +00:00
|
|
|
#include "misc.h"
|
1988-10-26 15:21:11 +00:00
|
|
|
#include "node.h"
|
|
|
|
#include "scope.h"
|
|
|
|
#include "type.h"
|
2019-02-23 17:15:23 +00:00
|
|
|
#include "code.h"
|
|
|
|
#include "chk_expr.h"
|
|
|
|
#include "typequiv.h"
|
|
|
|
#include "error.h"
|
|
|
|
#include "readwrite.h"
|
2019-02-23 16:44:50 +00:00
|
|
|
|
1988-10-26 15:21:11 +00:00
|
|
|
|
1989-05-03 10:30:22 +00:00
|
|
|
/* DEBUG */
|
|
|
|
#include "idf.h"
|
|
|
|
|
1991-04-25 16:26:11 +00:00
|
|
|
|
2016-11-10 21:04:18 +00:00
|
|
|
|
2019-02-23 16:44:50 +00:00
|
|
|
|
|
|
|
/* Internal function prototypes */
|
|
|
|
static int ChkWriteParameter(struct type *, struct node *, char *);
|
|
|
|
static void CodeRead(register struct node *, register struct node *);
|
|
|
|
static void CodeRead(register struct node *, register struct node *);
|
|
|
|
static void CodeReadln(struct node *);
|
|
|
|
static void CodeWrite(register struct node *, register struct node *);
|
|
|
|
static void CodeWriteln(register struct node *);
|
|
|
|
|
|
|
|
void ChkRead(register struct node *arg)
|
1988-10-26 15:21:11 +00:00
|
|
|
{
|
|
|
|
struct node *file;
|
|
|
|
char *name = "read";
|
1989-05-03 10:30:22 +00:00
|
|
|
char *message, buff[80];
|
2019-02-23 16:44:50 +00:00
|
|
|
|
1988-10-26 15:21:11 +00:00
|
|
|
|
|
|
|
assert(arg);
|
|
|
|
assert(arg->nd_symb == ',');
|
|
|
|
|
|
|
|
if( arg->nd_left->nd_type->tp_fund == T_FILE ) {
|
|
|
|
file = arg->nd_left;
|
|
|
|
arg = arg->nd_right;
|
|
|
|
if( !arg ) {
|
|
|
|
error("\"%s\": variable-access expected", name);
|
|
|
|
return;
|
|
|
|
}
|
1994-10-25 15:41:59 +00:00
|
|
|
MarkUsed(file);
|
1988-10-26 15:21:11 +00:00
|
|
|
}
|
|
|
|
else if( !(file = ChkStdInOut(name, 0)) )
|
|
|
|
return;
|
|
|
|
|
|
|
|
while( arg ) {
|
|
|
|
assert(arg->nd_symb == ',');
|
|
|
|
|
|
|
|
if( file->nd_type != text_type ) {
|
|
|
|
/* real var & file of integer */
|
|
|
|
if( !TstAssCompat(arg->nd_left->nd_type,
|
|
|
|
BaseType(file->nd_type->next)) ) {
|
|
|
|
node_error(arg->nd_left,
|
|
|
|
"\"%s\": illegal parameter type",name);
|
|
|
|
return;
|
|
|
|
}
|
1989-05-03 10:30:22 +00:00
|
|
|
else if( (BaseType(file->nd_type->next) == long_type
|
|
|
|
&& arg->nd_left->nd_type == int_type)
|
|
|
|
||
|
|
|
|
(BaseType(file->nd_type->next) == int_type
|
|
|
|
&& arg->nd_left->nd_type == long_type) ) {
|
|
|
|
if( int_size != long_size ) {
|
|
|
|
node_error(arg->nd_left,
|
|
|
|
"\"%s\": longs and integers have different sizes",name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else node_warning(arg->nd_left,
|
|
|
|
"\"%s\": mixture of longs and integers", name);
|
|
|
|
}
|
1988-10-26 15:21:11 +00:00
|
|
|
}
|
|
|
|
else if( !(BaseType(arg->nd_left->nd_type)->tp_fund &
|
|
|
|
( T_CHAR | T_NUMERIC )) ) {
|
|
|
|
node_error(arg->nd_left,
|
|
|
|
"\"%s\": illegal parameter type",name);
|
|
|
|
return;
|
|
|
|
}
|
1989-05-03 10:30:22 +00:00
|
|
|
message = ChkAllowedVar(arg->nd_left, 1);
|
|
|
|
if( message ) {
|
|
|
|
sprint(buff,"\"%%s\": %s can't be a variable parameter",
|
|
|
|
message);
|
|
|
|
node_error(arg->nd_left, buff, name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
1988-10-26 15:21:11 +00:00
|
|
|
CodeRead(file, arg->nd_left);
|
|
|
|
arg = arg->nd_right;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-23 16:44:50 +00:00
|
|
|
void ChkReadln(register struct node *arg)
|
1988-10-26 15:21:11 +00:00
|
|
|
{
|
|
|
|
struct node *file;
|
|
|
|
char *name = "readln";
|
1989-05-03 10:30:22 +00:00
|
|
|
char *message, buff[80];
|
2019-02-23 16:44:50 +00:00
|
|
|
|
1988-10-26 15:21:11 +00:00
|
|
|
|
|
|
|
if( !arg ) {
|
|
|
|
if( !(file = ChkStdInOut(name, 0)) )
|
|
|
|
return;
|
|
|
|
else {
|
|
|
|
CodeReadln(file);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(arg->nd_symb == ',');
|
|
|
|
|
|
|
|
if( arg->nd_left->nd_type->tp_fund == T_FILE ) {
|
|
|
|
if( arg->nd_left->nd_type != text_type ) {
|
|
|
|
node_error(arg->nd_left,
|
|
|
|
"\"%s\": textfile expected", name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
file = arg->nd_left;
|
|
|
|
arg = arg->nd_right;
|
1994-10-25 15:41:59 +00:00
|
|
|
MarkUsed(file);
|
1988-10-26 15:21:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if( !(file = ChkStdInOut(name, 0)) )
|
|
|
|
return;
|
|
|
|
|
|
|
|
while( arg ) {
|
|
|
|
assert(arg->nd_symb == ',');
|
|
|
|
|
|
|
|
if( !(BaseType(arg->nd_left->nd_type)->tp_fund &
|
|
|
|
( T_CHAR | T_NUMERIC )) ) {
|
|
|
|
node_error(arg->nd_left,
|
|
|
|
"\"%s\": illegal parameter type",name);
|
|
|
|
return;
|
|
|
|
}
|
1989-05-03 10:30:22 +00:00
|
|
|
message = ChkAllowedVar(arg->nd_left, 1);
|
|
|
|
if( message ) {
|
|
|
|
sprint(buff,"\"%%s\": %s can't be a variable parameter",
|
|
|
|
message);
|
|
|
|
node_error(arg->nd_left, buff, name);
|
|
|
|
return;
|
|
|
|
}
|
1988-10-26 15:21:11 +00:00
|
|
|
CodeRead(file, arg->nd_left);
|
|
|
|
arg = arg->nd_right;
|
|
|
|
}
|
|
|
|
CodeReadln(file);
|
|
|
|
}
|
|
|
|
|
2019-02-23 16:44:50 +00:00
|
|
|
void ChkWrite(register struct node *arg)
|
1988-10-26 15:21:11 +00:00
|
|
|
{
|
|
|
|
struct node *left, *expp, *file;
|
|
|
|
char *name = "write";
|
|
|
|
|
|
|
|
assert(arg);
|
|
|
|
assert(arg->nd_symb == ',');
|
|
|
|
assert(arg->nd_left->nd_symb == ':');
|
|
|
|
|
|
|
|
left = arg->nd_left;
|
|
|
|
expp = left->nd_left;
|
|
|
|
|
|
|
|
if( expp->nd_type->tp_fund == T_FILE ) {
|
|
|
|
if( left->nd_right ) {
|
|
|
|
node_error(expp,
|
|
|
|
"\"%s\": filevariable can't have a width",name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
file = expp;
|
1994-10-25 15:41:59 +00:00
|
|
|
MarkUsed(file);
|
1988-10-26 15:21:11 +00:00
|
|
|
arg = arg->nd_right;
|
|
|
|
if( !arg ) {
|
|
|
|
error("\"%s\": expression expected", name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if( !(file = ChkStdInOut(name, 1)) )
|
|
|
|
return;
|
|
|
|
|
|
|
|
while( arg ) {
|
|
|
|
assert(arg->nd_symb == ',');
|
|
|
|
|
|
|
|
if( !ChkWriteParameter(file->nd_type, arg->nd_left, name) )
|
|
|
|
return;
|
|
|
|
|
|
|
|
CodeWrite(file, arg->nd_left);
|
|
|
|
arg = arg->nd_right;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-23 16:44:50 +00:00
|
|
|
void ChkWriteln(register struct node *arg)
|
1988-10-26 15:21:11 +00:00
|
|
|
{
|
|
|
|
struct node *left, *expp, *file;
|
|
|
|
char *name = "writeln";
|
|
|
|
|
|
|
|
if( !arg ) {
|
|
|
|
if( !(file = ChkStdInOut(name, 1)) )
|
|
|
|
return;
|
|
|
|
else {
|
|
|
|
CodeWriteln(file);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(arg->nd_symb == ',');
|
|
|
|
assert(arg->nd_left->nd_symb == ':');
|
|
|
|
|
|
|
|
left = arg->nd_left;
|
|
|
|
expp = left->nd_left;
|
|
|
|
|
|
|
|
if( expp->nd_type->tp_fund == T_FILE ) {
|
|
|
|
if( expp->nd_type != text_type ) {
|
|
|
|
node_error(expp, "\"%s\": textfile expected", name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if( left->nd_right ) {
|
|
|
|
node_error(expp,
|
|
|
|
"\"%s\": filevariable can't have a width", name);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
file = expp;
|
1994-10-25 15:41:59 +00:00
|
|
|
MarkUsed(file);
|
1988-10-26 15:21:11 +00:00
|
|
|
arg = arg->nd_right;
|
|
|
|
}
|
|
|
|
else if( !(file = ChkStdInOut(name, 1)) )
|
|
|
|
return;
|
|
|
|
|
|
|
|
while( arg ) {
|
|
|
|
assert(arg->nd_symb == ',');
|
|
|
|
|
|
|
|
if( !ChkWriteParameter(text_type, arg->nd_left, name) )
|
|
|
|
return;
|
|
|
|
|
|
|
|
CodeWrite(file, arg->nd_left);
|
|
|
|
arg = arg->nd_right;
|
|
|
|
}
|
|
|
|
CodeWriteln(file);
|
|
|
|
}
|
|
|
|
|
2019-02-23 16:44:50 +00:00
|
|
|
static int ChkWriteParameter(struct type *filetype, struct node *arg, char *name)
|
1988-10-26 15:21:11 +00:00
|
|
|
{
|
|
|
|
struct type *tp;
|
|
|
|
char *mess = "illegal write parameter";
|
|
|
|
|
|
|
|
assert(arg->nd_symb == ':');
|
|
|
|
|
|
|
|
tp = BaseType(arg->nd_left->nd_type);
|
|
|
|
|
|
|
|
if( filetype == text_type ) {
|
1989-05-03 10:30:22 +00:00
|
|
|
if( !(tp == bool_type ||
|
|
|
|
tp->tp_fund & (T_CHAR | T_NUMERIC | T_STRING) ||
|
|
|
|
IsString(tp)) ) {
|
1988-10-26 15:21:11 +00:00
|
|
|
node_error(arg->nd_left, "\"%s\": %s", name, mess);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if( !TstAssCompat(BaseType(filetype->next), tp) ) {
|
|
|
|
node_error(arg->nd_left, "\"%s\": %s", name, mess);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if( arg->nd_right ) {
|
|
|
|
node_error(arg->nd_left, "\"%s\": %s", name, mess);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Here we have a text-file */
|
|
|
|
|
2019-02-23 16:44:50 +00:00
|
|
|
if( (arg = arg->nd_right) !=0 ) {
|
1988-10-26 15:21:11 +00:00
|
|
|
/* Total width */
|
|
|
|
|
|
|
|
assert(arg->nd_symb == ':');
|
|
|
|
if( BaseType(arg->nd_left->nd_type) != int_type ) {
|
|
|
|
node_error(arg->nd_left, "\"%s\": %s", name, mess);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return 1;
|
|
|
|
|
2019-02-23 16:44:50 +00:00
|
|
|
if( (arg = arg->nd_right)!=0 ) {
|
1988-10-26 15:21:11 +00:00
|
|
|
/* Fractional Part */
|
|
|
|
|
|
|
|
assert(arg->nd_symb == ':');
|
|
|
|
if( tp != real_type ) {
|
|
|
|
node_error(arg->nd_left, "\"%s\": %s", name, mess);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if( BaseType(arg->nd_left->nd_type) != int_type ) {
|
|
|
|
node_error(arg->nd_left, "\"%s\": %s", name, mess);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2019-02-23 16:44:50 +00:00
|
|
|
struct node *ChkStdInOut(char *name, int st_out)
|
1988-10-26 15:21:11 +00:00
|
|
|
{
|
|
|
|
register struct def *df;
|
|
|
|
register struct node *nd;
|
|
|
|
|
1989-05-03 10:30:22 +00:00
|
|
|
if( !(df = lookup(str2idf(st_out ? output : input, 0),
|
|
|
|
GlobalScope, D_INUSE)) ||
|
|
|
|
!(df->df_flags & D_PROGPAR) ) {
|
1988-10-26 15:21:11 +00:00
|
|
|
error("\"%s\": standard input/output not defined", name);
|
|
|
|
return NULLNODE;
|
|
|
|
}
|
|
|
|
|
|
|
|
nd = MkLeaf(Def, &dot);
|
|
|
|
nd->nd_def = df;
|
|
|
|
nd->nd_type = df->df_type;
|
1989-05-03 10:30:22 +00:00
|
|
|
df->df_flags |= D_USED;
|
1988-10-26 15:21:11 +00:00
|
|
|
|
|
|
|
return nd;
|
|
|
|
}
|
|
|
|
|
2019-02-23 16:44:50 +00:00
|
|
|
static void CodeRead(register struct node *file, register struct node *arg)
|
1988-10-26 15:21:11 +00:00
|
|
|
{
|
|
|
|
struct type *tp = BaseType(arg->nd_type);
|
|
|
|
|
|
|
|
if( err_occurred ) return;
|
|
|
|
|
|
|
|
CodeDAddress(file);
|
|
|
|
|
|
|
|
if( file->nd_type == text_type ) {
|
|
|
|
switch( tp->tp_fund ) {
|
|
|
|
case T_CHAR:
|
|
|
|
C_cal("_rdc");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case T_INTEGER:
|
|
|
|
C_cal("_rdi");
|
|
|
|
break;
|
|
|
|
|
1989-05-03 10:30:22 +00:00
|
|
|
case T_LONG:
|
|
|
|
C_cal("_rdl");
|
|
|
|
break;
|
|
|
|
|
1988-10-26 15:21:11 +00:00
|
|
|
case T_REAL:
|
|
|
|
C_cal("_rdr");
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
crash("(CodeRead)");
|
|
|
|
/*NOTREACHED*/
|
|
|
|
}
|
|
|
|
C_asp(pointer_size);
|
|
|
|
C_lfr(tp->tp_size);
|
|
|
|
RangeCheck(arg->nd_type, file->nd_type->next);
|
|
|
|
CodeDStore(arg);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* Keep the address of the file on the stack */
|
|
|
|
C_dup(pointer_size);
|
|
|
|
|
|
|
|
C_cal("_wdw");
|
|
|
|
C_asp(pointer_size);
|
|
|
|
C_lfr(pointer_size);
|
|
|
|
RangeCheck(arg->nd_type, file->nd_type->next);
|
|
|
|
|
|
|
|
C_loi(file->nd_type->next->tp_psize);
|
1989-05-03 10:30:22 +00:00
|
|
|
if( tp == real_type ) {
|
|
|
|
if( BaseType(file->nd_type->next) == int_type ||
|
|
|
|
BaseType(file->nd_type->next) == long_type )
|
|
|
|
Int2Real(file->nd_type->next->tp_psize);
|
|
|
|
}
|
1988-10-26 15:21:11 +00:00
|
|
|
|
|
|
|
CodeDStore(arg);
|
|
|
|
C_cal("_get");
|
|
|
|
C_asp(pointer_size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-23 16:44:50 +00:00
|
|
|
static void CodeReadln(struct node *file)
|
1988-10-26 15:21:11 +00:00
|
|
|
{
|
|
|
|
if( err_occurred ) return;
|
|
|
|
|
|
|
|
CodeDAddress(file);
|
|
|
|
C_cal("_rln");
|
|
|
|
C_asp(pointer_size);
|
|
|
|
}
|
|
|
|
|
2019-02-23 16:44:50 +00:00
|
|
|
static void CodeWrite(register struct node *file, register struct node *arg)
|
1988-10-26 15:21:11 +00:00
|
|
|
{
|
|
|
|
int width = 0;
|
|
|
|
register arith nbpars = pointer_size;
|
|
|
|
register struct node *expp = arg->nd_left;
|
|
|
|
struct node *right = arg->nd_right;
|
|
|
|
struct type *tp = BaseType(expp->nd_type);
|
|
|
|
|
|
|
|
if( err_occurred ) return;
|
|
|
|
|
|
|
|
CodeDAddress(file);
|
|
|
|
CodePExpr(expp);
|
|
|
|
|
|
|
|
if( file->nd_type == text_type ) {
|
1989-05-03 10:30:22 +00:00
|
|
|
if( tp->tp_fund & (T_ARRAY | T_STRINGCONST) ) {
|
1988-10-26 15:21:11 +00:00
|
|
|
C_loc(IsString(tp));
|
|
|
|
nbpars += pointer_size + int_size;
|
|
|
|
}
|
|
|
|
else nbpars += tp->tp_size;
|
|
|
|
|
|
|
|
if( right ) {
|
|
|
|
width = 1;
|
|
|
|
CodePExpr(right->nd_left);
|
|
|
|
nbpars += int_size;
|
|
|
|
right = right->nd_right;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch( tp->tp_fund ) {
|
|
|
|
case T_ENUMERATION: /* boolean */
|
|
|
|
C_cal(width ? "_wsb" : "_wrb");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case T_CHAR:
|
|
|
|
C_cal(width ? "_wsc" : "_wrc");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case T_INTEGER:
|
|
|
|
C_cal(width ? "_wsi" : "_wri");
|
|
|
|
break;
|
|
|
|
|
1989-05-03 10:30:22 +00:00
|
|
|
case T_LONG:
|
|
|
|
C_cal(width ? "_wsl" : "_wrl");
|
|
|
|
break;
|
|
|
|
|
1988-10-26 15:21:11 +00:00
|
|
|
case T_REAL:
|
|
|
|
if( right ) {
|
|
|
|
CodePExpr(right->nd_left);
|
|
|
|
nbpars += int_size;
|
|
|
|
C_cal("_wrf");
|
|
|
|
}
|
|
|
|
else C_cal(width ? "_wsr" : "_wrr");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case T_ARRAY:
|
1989-05-03 10:30:22 +00:00
|
|
|
case T_STRINGCONST:
|
1988-10-26 15:21:11 +00:00
|
|
|
C_cal(width ? "_wss" : "_wrs");
|
|
|
|
break;
|
|
|
|
|
1989-05-03 10:30:22 +00:00
|
|
|
case T_STRING:
|
|
|
|
C_cal(width ? "_wsz" : "_wrz");
|
|
|
|
break;
|
|
|
|
|
1988-10-26 15:21:11 +00:00
|
|
|
default:
|
1989-05-03 10:30:22 +00:00
|
|
|
crash("(CodeWrite)");
|
1988-10-26 15:21:11 +00:00
|
|
|
/*NOTREACHED*/
|
|
|
|
}
|
|
|
|
C_asp(nbpars);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if( file->nd_type->next == real_type && tp == int_type )
|
1989-05-03 10:30:22 +00:00
|
|
|
Int2Real(int_size);
|
|
|
|
else if( file->nd_type->next == real_type && tp == long_type )
|
|
|
|
Int2Real(long_size);
|
1988-10-26 15:21:11 +00:00
|
|
|
|
|
|
|
CodeDAddress(file);
|
|
|
|
C_cal("_wdw");
|
|
|
|
C_asp(pointer_size);
|
|
|
|
C_lfr(pointer_size);
|
|
|
|
C_sti(file->nd_type->next->tp_psize);
|
|
|
|
|
|
|
|
C_cal("_put");
|
|
|
|
C_asp(pointer_size);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-23 16:44:50 +00:00
|
|
|
static void CodeWriteln(register struct node *file)
|
1988-10-26 15:21:11 +00:00
|
|
|
{
|
|
|
|
if( err_occurred ) return;
|
|
|
|
|
|
|
|
CodeDAddress(file);
|
|
|
|
C_cal("_wln");
|
|
|
|
C_asp(pointer_size);
|
|
|
|
}
|