Initial revision
This commit is contained in:
684
lang/occam/comp/occam.g
Normal file
684
lang/occam/comp/occam.g
Normal file
@@ -0,0 +1,684 @@
|
||||
/* OCCAM */
|
||||
{
|
||||
#include "token.h"
|
||||
#include "symtab.h"
|
||||
#include "expr.h"
|
||||
#include "code.h"
|
||||
#include "sizes.h"
|
||||
|
||||
#define MAXERRORS 10 /* Maximum number of insert/delete errors */
|
||||
|
||||
static void nonconst(), nonpositive(), rep_cleanup(), check_assoc();
|
||||
void init_builtins();
|
||||
|
||||
extern int yylineno, LLsymb;
|
||||
union type_info info, none;
|
||||
}
|
||||
%token AFTER, ALLOCATE, ALT, AND, ANY, BYTE, CHAN, DEF, FALSE, FOR, IF, LOAD;
|
||||
%token NOT, NOW, OR, PAR, PLACED, PORT, PRI, PROC, SEQ, SKIP, TABLE, TRUE;
|
||||
%token VALUE, VAR, WAIT, WHILE;
|
||||
%token IDENTIFIER, NUMBER, CHAR_CONST, STRING;
|
||||
%token AS, LE, GE, NE, LS, RS, BA, BO, BX, BS;
|
||||
|
||||
%start occam, program;
|
||||
|
||||
program : { init_builtins();
|
||||
header();
|
||||
}
|
||||
process
|
||||
;
|
||||
|
||||
process : primitive
|
||||
| construct
|
||||
| { sym_down(); }
|
||||
declaration ':' process
|
||||
{ sym_up(); }
|
||||
;
|
||||
|
||||
primitive { struct expr *e; } :
|
||||
statement(&e) { if (!valueless(e))
|
||||
report("primitive may not have a value");
|
||||
code_void(e);
|
||||
destroy(e);
|
||||
}
|
||||
| WAIT val_expr(&e) { int BEGIN=0, END=0, TEST=0;
|
||||
check_wait(e);
|
||||
no_deadlock();
|
||||
branch(&TEST);
|
||||
Label(new_label(&BEGIN));
|
||||
resumenext();
|
||||
Label(TEST);
|
||||
code_bool(e, positive, &END, &BEGIN);
|
||||
Label(END);
|
||||
destroy(e);
|
||||
}
|
||||
| SKIP
|
||||
;
|
||||
|
||||
guard(register *F;) { struct expr *e1, *e2;
|
||||
register full_guard=0;
|
||||
int T=0;
|
||||
static char EXPECT_INP[]="input process expected as guard";
|
||||
} :
|
||||
expression(&e1)
|
||||
[ '&' { full_guard=1;
|
||||
if (!valued(e1))
|
||||
report("boolean part of guard has no value");
|
||||
code_bool(e1, positive, &T, F);
|
||||
Label(T);
|
||||
}
|
||||
[ statement(&e2)
|
||||
{ if (!input_process(e2))
|
||||
report(EXPECT_INP);
|
||||
code_any(e2, F);
|
||||
destroy(e2);
|
||||
}
|
||||
| WAIT val_expr(&e2)
|
||||
{ check_wait(e2);
|
||||
code_bool(e2, positive, &T, F);
|
||||
Label(T);
|
||||
destroy(e2);
|
||||
}
|
||||
| SKIP
|
||||
]
|
||||
]?
|
||||
{ if (!full_guard) {
|
||||
if (!input_process(e1))
|
||||
report(EXPECT_INP);
|
||||
code_any(e1, F);
|
||||
}
|
||||
destroy(e1);
|
||||
}
|
||||
| WAIT val_expr(&e1)
|
||||
{ check_wait(e1);
|
||||
code_bool(e1, positive, &T, F);
|
||||
Label(T);
|
||||
destroy(e1);
|
||||
}
|
||||
| SKIP
|
||||
;
|
||||
|
||||
guarded_process(register *END;) { struct symbol *v;
|
||||
struct expr *e1, *e2;
|
||||
struct replicator to_test;
|
||||
register line, oind;
|
||||
int F=0;
|
||||
} :
|
||||
guard(&F) process { branch(END);
|
||||
Label(F);
|
||||
}
|
||||
| ALT { line=yylineno; oind=ind; }
|
||||
[ %if (line==yylineno)
|
||||
replicator(&v, &e1, &e2)
|
||||
{ rep_init(v, e1, e2, &to_test); }
|
||||
guarded_process(END)
|
||||
{ rep_test(v, e1, e2, &to_test);
|
||||
rep_cleanup(e1, e2);
|
||||
}
|
||||
|
|
||||
[ %while (tabulated(oind, ind)) guarded_process(END) ]*
|
||||
]
|
||||
;
|
||||
|
||||
conditional(register *END; ) { struct symbol *v;
|
||||
struct expr *e1, *e2;
|
||||
struct replicator to_test;
|
||||
register line, oind;
|
||||
int T=0, F=0;
|
||||
} :
|
||||
val_expr(&e1) { if (!valued(e1))
|
||||
report("conditional needs valued expression");
|
||||
code_bool(e1, positive, &T, &F);
|
||||
Label(T);
|
||||
destroy(e1);
|
||||
}
|
||||
process
|
||||
{ branch(END);
|
||||
Label(F);
|
||||
}
|
||||
| IF { line=yylineno; oind=ind; }
|
||||
[ %if (line==yylineno)
|
||||
replicator(&v, &e1, &e2)
|
||||
{ rep_init(v, e1, e2, &to_test); }
|
||||
conditional(END)
|
||||
{ rep_test(v, e1, e2, &to_test);
|
||||
rep_cleanup(e1, e2);
|
||||
}
|
||||
|
|
||||
[ %while (tabulated(oind, ind)) conditional(END) ]*
|
||||
]
|
||||
;
|
||||
|
||||
replicator(register struct symbol **s; register struct expr **e1, **e2; )
|
||||
{ register char *index; }:
|
||||
IDENTIFIER { index=token.t_sval; }
|
||||
'=' '[' val_expr(e1) FOR val_expr(e2) ']'
|
||||
{ if (!valued(*e1) || !valued(*e2))
|
||||
report("replicator needs valued expressions");
|
||||
sym_down();
|
||||
var_memory(&info, T_VAR, 1);
|
||||
*s=insert(index,
|
||||
T_VAR|T_REP|T_USED|T_ASSIGNED, 1, info);
|
||||
}
|
||||
;
|
||||
|
||||
construct { struct symbol *v;
|
||||
struct expr *e1, *e2;
|
||||
struct replicator to_test;
|
||||
register line, oind;
|
||||
int BEGIN=0, END=0, NONZERO;
|
||||
}:
|
||||
SEQ { line=yylineno; oind=ind; }
|
||||
[ %if (line==yylineno)
|
||||
replicator(&v, &e1, &e2)
|
||||
{ rep_init(v, e1, e2, &to_test); }
|
||||
process
|
||||
{ rep_test(v, e1, e2, &to_test);
|
||||
rep_cleanup(e1, e2);
|
||||
}
|
||||
|
|
||||
[ %while (tabulated(oind, ind)) process ]*
|
||||
]
|
||||
| PRI ?
|
||||
[ PAR { line=yylineno; oind=ind;
|
||||
par_begin();
|
||||
}
|
||||
[ %if (line==yylineno)
|
||||
replicator(&v, &e1, &e2)
|
||||
{ rep_init(v, e1, e2, &to_test);
|
||||
NONZERO=0;
|
||||
par_fork(&NONZERO);
|
||||
}
|
||||
process
|
||||
{ branch(&END);
|
||||
Label(NONZERO);
|
||||
rep_test(v, e1, e2, &to_test);
|
||||
rep_cleanup(e1, e2);
|
||||
}
|
||||
|
|
||||
[ %while (tabulated(oind, ind))
|
||||
{ NONZERO=0;
|
||||
par_fork(&NONZERO);
|
||||
}
|
||||
process
|
||||
{ branch(&END);
|
||||
Label(NONZERO);
|
||||
}
|
||||
]*
|
||||
]
|
||||
{ Label(END);
|
||||
par_end();
|
||||
}
|
||||
| ALT { line=yylineno; oind=ind;
|
||||
no_deadlock();
|
||||
Label(new_label(&BEGIN));
|
||||
}
|
||||
[ %if (line==yylineno)
|
||||
replicator(&v, &e1, &e2)
|
||||
{ rep_init(v, e1, e2, &to_test); }
|
||||
guarded_process(&END)
|
||||
{ rep_test(v, e1, e2, &to_test);
|
||||
rep_cleanup(e1, e2);
|
||||
}
|
||||
|
|
||||
[ %while (tabulated(oind, ind)) guarded_process(&END)
|
||||
]*
|
||||
]
|
||||
{ resumenext();
|
||||
branch(&BEGIN);
|
||||
Label(END);
|
||||
}
|
||||
]
|
||||
| IF { line=yylineno; oind=ind; }
|
||||
[ %if (line==yylineno)
|
||||
replicator(&v, &e1, &e2)
|
||||
{ rep_init(v, e1, e2, &to_test); }
|
||||
conditional(&END)
|
||||
{ rep_test(v, e1, e2, &to_test);
|
||||
rep_cleanup(e1, e2);
|
||||
}
|
||||
|
|
||||
[ %while (tabulated(oind, ind)) conditional(&END) ]*
|
||||
]
|
||||
{ Label(END); }
|
||||
| WHILE val_expr(&e1) { if (!valued(e1))
|
||||
report("WHILE needs valued expression");
|
||||
branch(&END);
|
||||
Label(new_label(&BEGIN));
|
||||
}
|
||||
process
|
||||
{ int DONE=0;
|
||||
Label(END);
|
||||
code_bool(e1, negative, &DONE, &BEGIN);
|
||||
Label(DONE);
|
||||
destroy(e1);
|
||||
}
|
||||
;
|
||||
|
||||
subscript(register *byte; register struct expr **e; )
|
||||
{ struct expr *e1;
|
||||
register slice=0, err=0;
|
||||
} :
|
||||
'[' { *byte=0; }
|
||||
[ BYTE { *byte=T_BYTE; }
|
||||
]?
|
||||
val_expr(e) { if (!valued(*e))
|
||||
err++;
|
||||
}
|
||||
[ FOR expression(&e1)
|
||||
{ static char siz[]="slize size";
|
||||
if (!constant(e1)) {
|
||||
if (!err)
|
||||
nonconst(siz);
|
||||
destroy(e1);
|
||||
e1=new_const(0L);
|
||||
} else
|
||||
if (e1->u.const<=0)
|
||||
nonpositive(siz);
|
||||
*e=new_node(FOR, *e, e1);
|
||||
slice=1;
|
||||
}
|
||||
]?
|
||||
']'
|
||||
{ if (err)
|
||||
report(slice ?
|
||||
"slice must be '[' value FOR constant ']'" :
|
||||
"subscript needs valued expression");
|
||||
}
|
||||
;
|
||||
|
||||
chan { register type, arr_siz=1; register char *name; struct expr *e; }:
|
||||
IDENTIFIER { type=T_CHAN;
|
||||
name=token.t_sval;
|
||||
}
|
||||
[ '[' expression(&e) ']'
|
||||
{ static char siz[]="channel array size";
|
||||
if (!constant(e))
|
||||
nonconst(siz);
|
||||
else
|
||||
if (e->u.const<0)
|
||||
nonpositive(siz);
|
||||
else
|
||||
arr_siz=e->u.const;
|
||||
destroy(e);
|
||||
type|=T_ARR;
|
||||
}
|
||||
]?
|
||||
{ chan_memory(&info, arr_siz);
|
||||
chan_init(&info, arr_siz);
|
||||
insert(name, type, arr_siz, info);
|
||||
}
|
||||
;
|
||||
|
||||
var { register type, byte=0, arr_siz=1;
|
||||
register char *name;
|
||||
struct expr *e;
|
||||
}:
|
||||
IDENTIFIER { type=T_VAR; name=token.t_sval; }
|
||||
[ '['
|
||||
[ BYTE { byte=T_BYTE; }
|
||||
]?
|
||||
expression(&e) ']'
|
||||
{ static char siz[]="variable array size";
|
||||
if (!constant(e))
|
||||
nonconst(siz);
|
||||
else
|
||||
if (e->u.const<=0)
|
||||
nonpositive(siz);
|
||||
else
|
||||
arr_siz=e->u.const;
|
||||
destroy(e);
|
||||
type|=T_ARR|byte;
|
||||
}
|
||||
]?
|
||||
{ var_memory(&info, type, arr_siz);
|
||||
insert(name, type, arr_siz, info);
|
||||
}
|
||||
;
|
||||
|
||||
const_def { register char *name; struct expr *e; }:
|
||||
IDENTIFIER { name=token.t_sval; }
|
||||
'=' expression(&e)
|
||||
{ if (!constant(e) && !arr_constant(e))
|
||||
nonconst("expression in constant definition");
|
||||
info.const=e;
|
||||
insert(name, T_CONST|T_USED, 0, info);
|
||||
}
|
||||
;
|
||||
|
||||
form_parm(register struct par_list ***aapars; register *g_type;)
|
||||
{ register char *name;
|
||||
register type= *g_type;
|
||||
}:
|
||||
[ VAR { type=T_VAR|T_ASSIGNED|T_USED; }
|
||||
| CHAN { type=T_CHAN; }
|
||||
| VALUE { type=T_VALUE|T_ASSIGNED; }
|
||||
]?
|
||||
IDENTIFIER {
|
||||
if (type<0) {
|
||||
report("VAR, CHAN or VALUE expected");
|
||||
type=T_VAR;
|
||||
}
|
||||
name=token.t_sval;
|
||||
*g_type=type;
|
||||
}
|
||||
[ '[' ']'
|
||||
{ type|=T_ARR; }
|
||||
]?
|
||||
{ pars_add(aapars, type&(T_TYPE|T_ARR),
|
||||
insert(name, type|T_PARAM, 0, none));
|
||||
}
|
||||
;
|
||||
|
||||
form_parms(struct par_list **apars;) { int type= -1; }:
|
||||
'(' form_parm(&apars, &type)
|
||||
[ ',' form_parm(&apars, &type)
|
||||
]*
|
||||
')'
|
||||
;
|
||||
|
||||
declaration:
|
||||
VAR
|
||||
var [ ',' var ]*
|
||||
| CHAN
|
||||
chan [ ',' chan ]*
|
||||
| DEF
|
||||
const_def [ ',' const_def ]*
|
||||
| proc_declaration
|
||||
;
|
||||
|
||||
proc_declaration { struct par_list *pars=nil;
|
||||
register struct symbol *proc;
|
||||
int OVER=0;
|
||||
register old_min_offset;
|
||||
}:
|
||||
PROC IDENTIFIER { branch(&OVER);
|
||||
proc=insert(token.t_sval,
|
||||
T_PROC|T_RECURS, 0, none);
|
||||
old_min_offset=min_offset;
|
||||
sym_down();
|
||||
prologue(proc);
|
||||
}
|
||||
form_parms(&pars) ? { form_offsets(pars);
|
||||
proc->info.proc.pars=pars;
|
||||
}
|
||||
'=' process { epilogue(proc);
|
||||
sym_up();
|
||||
proc->type&= ~T_RECURS;
|
||||
min_offset=old_min_offset;
|
||||
Label(OVER);
|
||||
}
|
||||
;
|
||||
|
||||
vector_constant(register struct expr **e;)
|
||||
{ struct table *pt=nil, **apt= &pt;
|
||||
register Tlen=0;
|
||||
}:
|
||||
table(e)
|
||||
| STRING { register char *ps= token.t_sval;
|
||||
register len;
|
||||
|
||||
Tlen+= len= (*ps++ & 0377);
|
||||
while (--len>=0)
|
||||
table_add(&apt, (long) *ps++);
|
||||
}
|
||||
[ %while (1) STRING
|
||||
{ register char *ps= token.t_sval;
|
||||
register len;
|
||||
|
||||
Tlen+= len= (*ps++ & 0377);
|
||||
while (--len>=0)
|
||||
table_add(&apt, (long) *ps++);
|
||||
}
|
||||
]*
|
||||
{ apt= &pt;
|
||||
table_add(&apt, (long) Tlen);
|
||||
*e=new_table(E_BTAB, pt);
|
||||
}
|
||||
;
|
||||
|
||||
item(register struct expr **e;)
|
||||
{ struct expr *e1;
|
||||
register struct symbol *var;
|
||||
struct par_list *pars=nil;
|
||||
register line, oind;
|
||||
int byte, err=0, subs_call=0;
|
||||
struct expr_list *elp=nil, **aelp= &elp;
|
||||
}:
|
||||
IDENTIFIER { line=yylineno;
|
||||
oind=ind;
|
||||
var=searchall(token.t_sval);
|
||||
|
||||
if (var_constant(var))
|
||||
*e=copy_const(var->info.const);
|
||||
else {
|
||||
if (var_proc(var))
|
||||
pars=var->info.proc.pars;
|
||||
*e=new_var(var);
|
||||
}
|
||||
}
|
||||
[ %while (line==yylineno || tabulated(oind, ind))
|
||||
[ subscript(&byte, &e1)
|
||||
{ *e=new_node('[', *e, e1, byte); }
|
||||
| '(' { if (!var_declared(var)) {
|
||||
var->type=T_PROC|T_USED|T_NOTDECL;
|
||||
var->info.proc.pars=nil;
|
||||
err=1;
|
||||
}
|
||||
if (!var_proc(var)) {
|
||||
report("%s is not a named process",
|
||||
var->name);
|
||||
err=1;
|
||||
}
|
||||
}
|
||||
expression(&e1)
|
||||
{ check_param(&pars, e1, &err);
|
||||
expr_list_add(&aelp, e1);
|
||||
}
|
||||
[ ',' expression(&e1)
|
||||
{ check_param(&pars, e1, &err);
|
||||
expr_list_add(&aelp, e1);
|
||||
}
|
||||
]*
|
||||
{
|
||||
if (pars!=nil)
|
||||
report("too few actual parameters");
|
||||
}
|
||||
')'
|
||||
{ *e=new_call(*e, elp); }
|
||||
]
|
||||
{ subs_call=1; }
|
||||
]?
|
||||
{ if (!subs_call && var_proc(var)) {
|
||||
if (pars!=nil)
|
||||
report("no actual parameters");
|
||||
*e=new_call(*e, nil);
|
||||
}
|
||||
}
|
||||
| vector_constant(e)
|
||||
[ subscript(&byte, &e1)
|
||||
{ *e=new_node('[', *e, e1, byte); }
|
||||
]?
|
||||
;
|
||||
|
||||
statement(register struct expr **e;)
|
||||
{ struct expr *e1;
|
||||
struct expr_list *elp=nil, **aelp= &elp;
|
||||
register out;
|
||||
}:
|
||||
item(e)
|
||||
[ AS expression(&e1)
|
||||
{ *e=new_node(AS, *e, e1); }
|
||||
| [
|
||||
'?' { out=0; }
|
||||
| '!' { out=1; }
|
||||
]
|
||||
io_arg(&e1)
|
||||
{ if (e1!=nil) check_io(out, e1);
|
||||
expr_list_add(&aelp, e1);
|
||||
}
|
||||
[ %while (1) ';' io_arg(&e1)
|
||||
{ if (e1!=nil) check_io(out, e1);
|
||||
expr_list_add(&aelp, e1);
|
||||
}
|
||||
]*
|
||||
{ *e=new_io(out, *e, elp); }
|
||||
]?
|
||||
;
|
||||
|
||||
io_arg(struct expr **e; ) :
|
||||
expression(e)
|
||||
| ANY { *e=nil; }
|
||||
;
|
||||
|
||||
table(register struct expr **e;)
|
||||
{ struct table *pt=nil, **apt= &pt;
|
||||
struct expr *e1;
|
||||
register type;
|
||||
}:
|
||||
TABLE '[' { type=E_TABLE; }
|
||||
[ BYTE { type=E_BTAB; }
|
||||
]?
|
||||
expression(&e1) { if (!constant(e1))
|
||||
nonconst("table element");
|
||||
else
|
||||
table_add(&apt, e1->u.const);
|
||||
destroy(e1);
|
||||
}
|
||||
[ ',' expression(&e1)
|
||||
{ if (!constant(e1))
|
||||
nonconst("table element");
|
||||
else
|
||||
table_add(&apt, e1->u.const);
|
||||
destroy(e1);
|
||||
}
|
||||
]*
|
||||
{ *e=new_table(type, pt); }
|
||||
']'
|
||||
;
|
||||
|
||||
arithmetic_op: '+' | '-' | '*' | '/' | BS
|
||||
;
|
||||
|
||||
comparison_op: '<' | '>' | LE | GE | NE | '=' | AFTER
|
||||
;
|
||||
|
||||
logical_op: BA | BO | BX
|
||||
;
|
||||
|
||||
boolean_op: AND | OR
|
||||
;
|
||||
|
||||
shift_op: LS | RS
|
||||
;
|
||||
|
||||
monadic_op(register *op;):
|
||||
'-' { *op='~'; }
|
||||
| NOT { *op=NOT; }
|
||||
;
|
||||
|
||||
operator: arithmetic_op | comparison_op | logical_op | boolean_op | shift_op
|
||||
;
|
||||
|
||||
element(register struct expr **e;) :
|
||||
%default NUMBER { *e=new_const(token.t_lval); }
|
||||
| statement(e)
|
||||
| TRUE { *e=new_const(-1L); }
|
||||
| FALSE { *e=new_const(0L); }
|
||||
| NOW { *e=new_now(); }
|
||||
| CHAR_CONST { *e=new_const(token.t_lval); }
|
||||
| '(' expression(e) ')' { if (valueless(*e))
|
||||
warning("primitive should not be parenthesized");
|
||||
}
|
||||
;
|
||||
|
||||
expression(register struct expr **e;)
|
||||
{ int op=0;
|
||||
struct expr *e1;
|
||||
}:
|
||||
element(e)
|
||||
[ %while (1) { if (op!=0) check_assoc(op, LLsymb);
|
||||
op=LLsymb;
|
||||
}
|
||||
operator element(&e1)
|
||||
{ *e=new_node(op, *e, e1); }
|
||||
]*
|
||||
| monadic_op(&op) element(&e1)
|
||||
{ *e=new_node(op, e1, nil); }
|
||||
;
|
||||
|
||||
val_expr(register struct expr **e;) :
|
||||
expression(e) { used(*e); }
|
||||
;
|
||||
|
||||
%lexical scanner;
|
||||
{
|
||||
int err=0;
|
||||
#include <stdio.h>
|
||||
|
||||
main(argc, argv) register argc; register char **argv;
|
||||
{
|
||||
wz= (argc>1 && strcmp(argv[1], "4")==0) ? 4 : 2;
|
||||
pz= (argc>2 && strcmp(argv[2], "4")==0) ? 4 : wz;
|
||||
|
||||
leader();
|
||||
occam();
|
||||
trailer();
|
||||
|
||||
exit(err);
|
||||
}
|
||||
|
||||
LLmessage(tk) register tk;
|
||||
{
|
||||
static errors=0;
|
||||
|
||||
if (tk>0) {
|
||||
repeat_token(LLsymb);
|
||||
warning("syntax error: %s expected (inserted)", tokenname(tk, 1));
|
||||
} else
|
||||
if (tk==0)
|
||||
warning("syntax error: bad token %s (deleted)", tokenname(LLsymb, 0));
|
||||
else { /* tk<0 */
|
||||
fprintf(stderr, "Compiler stack overflow. Compiler ends.");
|
||||
err=1; trailer(); exit(1);
|
||||
}
|
||||
if (++errors==MAXERRORS) {
|
||||
fprintf(stderr, "Too many insert/delete errors. Compiler ends.\n");
|
||||
err=1; trailer(); exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static void nonconst(siz) char *siz;
|
||||
{
|
||||
report("%s should be a constant", siz);
|
||||
}
|
||||
|
||||
static void nonpositive(siz) char *siz;
|
||||
{
|
||||
report("%s must be positive", siz);
|
||||
}
|
||||
|
||||
static void rep_cleanup(e1, e2) struct expr *e1, *e2;
|
||||
{
|
||||
destroy(e1);
|
||||
destroy(e2);
|
||||
sym_up();
|
||||
}
|
||||
|
||||
static void check_assoc(prev_op, op) register prev_op, op;
|
||||
{
|
||||
switch (op) {
|
||||
char prev[5];
|
||||
case '+': case '*':
|
||||
case AND: case OR:
|
||||
case BA: case BO: case BX:
|
||||
if (prev_op==op) break;
|
||||
default:
|
||||
strcpy(prev, tokenname(prev_op, 0));
|
||||
|
||||
warning("Operators %s and %s don't associate",
|
||||
prev, tokenname(op, 0)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user