commit 810119b44fdb4cff269d676d4bd5ca4061b94c28
parent 3ffc6b6c22cbaac8f8d11d344e13fbd195551dc9
Author: m21c <ho*******@gmail.com>
Date: Thu, 15 Jul 2021 13:35:44 +0200
minor code cleanup + changed SrcLoc in makedecl
Diffstat:
| M | aria.c | | | 169 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- |
1 file changed, 166 insertions(+), 3 deletions(-)
diff --git a/aria.c b/aria.c
@@ -904,12 +904,14 @@ skipwhite:
source->lastindent = 0;
return source->tok.kind = 0;
}
+
c0 = source->line[(source->currloc.column = 0)];
}
if (source->currloc.column) {
while (isspace(c0))
c0 = source->line[++source->currloc.column];
+
} else {
source->lastindent = 0;
while (isspace(c0)) {
@@ -1057,9 +1059,9 @@ skipwhite:
} else if (*end == 'l' || *end == 'L') {
source->tok.type = prim + TDOUBLE;
+
if (end[1])
goto errorfloat;
-
} else if (!mystrcasecmp(end, "f32") ||
!mystrcasecmp(end, "r32"))
{
@@ -1108,31 +1110,39 @@ skipwhite:
++end;
if (*end == 0) {
typeid += TINFER;
+
break;
} else if (*end == '8') {
typeid += TS8;
+
if (end[1])
goto errorint;
break;
} else if (!strcmp(end, "16")) {
typeid += TS16;
+
break;
} else if (!strcmp(end, "32")) {
typeid += TS32;
+
break;
} else if (!strcmp(end, "64")) {
typeid += TS64;
+
break;
} else if (!mystrcasecmp(end, "sz")) {
typeid += TSSIZE;
+
break;
}
default:
if (!mystrcasecmp(end, "ll")) {
typeid += TLLONG;
+
} else if (*end == 'l' || *end == 'L') {
typeid += TLONG;
+
if (end[1])
goto errorint;
} else {
@@ -1141,6 +1151,7 @@ skipwhite:
&source->currloc,
"invalid integer format"
);
+
typeid = TINT;
}
}
@@ -1154,6 +1165,7 @@ skipwhite:
/* string & character-literal */
if (c0 == '"' || c0 == '\'') {
int delim = c0, j;
+
c0 = source->line[++source->currloc.column];
source->tok.loc.column = source->currloc.column;
@@ -1161,28 +1173,36 @@ skipwhite:
while (c0 != delim && c0 != 0) {
if (c0 == '\\') {
c0 = source->line[++source->currloc.column];
+
switch (c0) {
case '\\':
c0 = '\\';
break;
+
case 'n':
c0 = '\n';
break;
+
case 'r':
c0 = '\r';
break;
+
case 't':
c0 = '\t';
break;
+
case '\'':
c0 = '\'';
break;
+
case '"':
c0 = '"';
break;
+
/* TODO(m21c): read more escape sequences */
case 0:
goto stringeol;
+
default:
error(
&source->currloc,
@@ -1191,9 +1211,11 @@ skipwhite:
);
}
}
+
source->line[j++] = c0;
c0 = source->line[++source->currloc.column];
}
+
++source->currloc.column;
source->line[j++] = 0;
@@ -1203,6 +1225,7 @@ skipwhite:
&source->currloc,
"unexpected end-of-line"
);
+
return source->tok.kind = '\n';
}
@@ -1212,6 +1235,7 @@ skipwhite:
source->line + source->tok.loc.column,
j - source->tok.loc.column
);
+
return source->tok.kind = 'S';
}
@@ -1226,10 +1250,12 @@ skipwhite:
case ']':
case ')':
goto joindelim;
+
case '[':
if (haslhs)
c0 = OARRAY;
goto joindelim;
+
case '(':
if (haslhs)
c0 = OCALL;
@@ -1249,21 +1275,26 @@ skipwhite:
/* tok.kind = select('.', ORANGE, ODISP); */
source->tok.kind = ODISP;
goto joinop;
+
case '*':
source->tok.kind = select('=', OMULA, (haslhs ? OMUL : OLPTR));
goto joinop;
+
case '/':
source->tok.kind = select('=', ODIVA, ODIV);
goto joinop;
+
case '%':
source->tok.kind = select('=', OMODA, OMOD);
goto joinop;
+
case '<':
source->tok.kind = select('=', OLEQ,
select('<',
select('=', OLSHA, OLSH),
OLET));
goto joinop;
+
case '>':
source->tok.kind = select('=', OGEQ,
select('>',
@@ -1272,32 +1303,40 @@ skipwhite:
select('=', ORSHA, ORSH)),
OGRT));
goto joinop;
+
case '&':
source->tok.kind = select('=', OANDA, select('&', OLAND,
/*(haslhs ? OBAND : ORPTR)*/ OBAND));
goto joinop;
+
case '+':
source->tok.kind = select('=', OADDA, select('+',
(haslhs ? OSUFINC : OINC),
(haslhs ? OADD : OPLUS)));
goto joinop;
+
case '-':
source->tok.kind = select('=', OSUBA, select('-',
(haslhs ? OSUFDEC : ODEC),
(haslhs ? OSUB : OMINUS)));
goto joinop;
+
case '|':
source->tok.kind = select('=', OORA, select('|', OLOR, OBOR));
goto joinop;
+
case '^':
source->tok.kind = select('=', OXORA, OXOR);
goto joinop;
+
case '!':
source->tok.kind = select('=', ONEQ, OLNOT);
goto joinop;
+
case '~':
source->tok.kind = select('=', OFLIP, OBNOT);
goto joinop;
+
case '=':
source->tok.kind = select('=', select('=', OIDENT, OEQU), OASS);
joinop:
@@ -1477,6 +1516,7 @@ makedecl(Source *source, int key, DeclKind kind) {
Decl *probe, *decl = declbuf + decltop++;
decl->kind = kind;
+ decl->loc = source->tok.loc;
decl->key = key;
decl->type = prim + TVOID;
decl->functionenv = NULL;
@@ -1486,9 +1526,8 @@ makedecl(Source *source, int key, DeclKind kind) {
probe = finddeclinenv(key, currenv);
if (probe) {
- /* TODO(m21c): obtain SrcLoc properly */
error(
- &probe->loc,
+ &source->tok.loc,
"'%s' already declared",
getstring(idents, key)
);
@@ -1536,6 +1575,7 @@ expect(Source *source, int kind, bool nexthaslhs, const char *fmt, ...) {
vfprintf(stderr, fmt, ap);
fprintf(stderr, "\n");
va_end(ap);
+
return false;
}
@@ -1554,30 +1594,38 @@ qualifiers(Source *source, int allowmask) {
case KEXTERN:
f = QEXTERN, m = ~QVISIB;
break;
+
case KINTERN:
f = QINTERN, m = ~QVISIB;
break;
+
case KSTATIC:
f = QSTATIC, m = ~QSTORAGE;
break;
+
case KCONST:
f = QCONST;
break;
+
case KVAR:
f = QVAR, m = ~(QTYPE | QINFER);
break;
+
default:
goto finish;
}
if (f & ~allowmask) {
const char *str = nodestrings[getkind(source)];
+
error(getloc(source), "invalid qualifier '%s'", str);
} else if (f & flags & QTYPE) {
const char *str = nodestrings[getkind(source)];
+
warn(getloc(source), "redundant qualifier '%s'", str);
} else if (f & ~mask) {
const char *str = nodestrings[getkind(source)];
+
error(getloc(source), "redundant qualifier '%s'", str);
}
@@ -1625,8 +1673,10 @@ advance:
tmp->kind = TARRAY;
tmp->target = basetype, basetype = tmp;
gettok(source, false);
+
if (source->tok.kind != ']')
basetype->u.val = expr(source, PSTART);
+
expect(source, ']', false, "expect ']'");
goto advance;
}
@@ -1635,6 +1685,7 @@ advance:
Type *tmp = maketype();
tmp->kind = TPTR;
tmp->target = basetype, basetype = tmp;
+
gettok(source, false);
goto advance;
}
@@ -1678,8 +1729,10 @@ declaration(Source *source, Type *ty) {
result->type = ty;
result->u.declref = decl;
gettok(source, true);
+
} else if (getkind(source) == 'T') {
Type *module = gettype(source, getbasetype(source, 0));
+
if (getkind(source) == ODISP || getkind(source) == ':') {
has_self_param = getkind(source) == ':';
gettok(source, false);
@@ -1706,10 +1759,12 @@ declaration(Source *source, Type *ty) {
} else {
error(getloc(source), "expected identifier");
}
+
} else {
result = makenode(&source->tok, NULL);
result->kind = 'T';
result->type = ty;
+
return result;
}
@@ -1924,6 +1979,7 @@ atom(Source *source, int flags) {
lhs = makenode(&source->tok, NULL);
gettok(source, false);
lhs->lhs = atom(source, 0);
+
return lhs;
}
@@ -1948,6 +2004,7 @@ atom(Source *source, int flags) {
gettok(source, false);
skipnewline(source);
lhs = exprlist(source, false, NULL), source->lastis = savedis;
+
if (lhs->kind == 'T') {
/* NOTE(m21c): expecting that the type is also set in lhs->type */
lhs->kind = OCAST;
@@ -1957,10 +2014,12 @@ atom(Source *source, int flags) {
lhs->lhs = atom(source, 0);
break;
}
+
skipnewline(source);
expect(source, ')', true, "expected ')'");
#else
gettok(source, false);
+
if (getkind(source) == '\n') {
lhs = stmtlist(source, source->lastindent, SSCOPE);
source->lastis = savedis;
@@ -1977,8 +2036,10 @@ atom(Source *source, int flags) {
lhs->lhs = atom(source, 0);
break;
}
+
skipnewline(source);
}
+
expect(source, ')', true, "expected ')'");
#endif
break;
@@ -2021,28 +2082,36 @@ atom(Source *source, int flags) {
if (flags & QCONST) {
/* TODO(m21c): const - conversion */
}
+
break;
+
case 'T':
case 'N':
case 'S':
case 'C':
lhs = makenode(&source->tok, NULL);
gettok(source, true);
+
if (flags & QCONST) {
/* TODO(m21c): const - conversion */
}
+
break;
+
case KNOT:
lhs = makenode(&source->tok, NULL);
gettok(source, false);
lhs->kind = OLNOT;
lhs->lhs = expr(source, PRELAT);
+
break;
+
case KBREAK:
case KCONTINUE:
lhs = makenode(&source->tok, NULL);
lhs->kind = getkind(source) == KBREAK ? ABREAK : ACONTINUE;
gettok(source, true);
+
if (getkind(source) == ':') {
gettok(source, false);
skipnewline(source);
@@ -2053,11 +2122,14 @@ atom(Source *source, int flags) {
error(getloc(source), "expected identifier");
}
}
+
break;
+
case KRETURN:
lhs = makenode(&source->tok, NULL);
gettok(source, true);
lhs->kind = ARETURN;
+
if (getkind(source) == ':') {
gettok(source, false);
skipnewline(source);
@@ -2068,16 +2140,20 @@ atom(Source *source, int flags) {
error(getloc(source), "expected identifier");
}
}
+
if (isatom(source))
lhs->rhs = exprlist(source, false, NULL);
break;
+
case KDO:
indent = source->lastindent;
lhs = makenode(&source->tok, NULL);
gettok(source, false);
lhs->kind = ADO;
lhs->lhs = stmtlist(source, indent, SSCOPE);
+
break;
+
case KLOOP:
indent = source->lastindent;
lhs = makenode(&source->tok, NULL);
@@ -2090,10 +2166,12 @@ atom(Source *source, int flags) {
gettok(source, false);
lhs->u.payload = expr(source, POR);
}
+
if (lhs->kind != ALOOP)
goto joinelse;
else
break;
+
case KWHILE:
indent = source->lastindent;
lhs = makenode(&source->tok, NULL);
@@ -2101,7 +2179,9 @@ atom(Source *source, int flags) {
lhs->kind = AWHILE;
lhs->u.payload = expr(source, POR);
lhs->lhs = stmtlist(source, indent, SSCOPE);
+
goto joinelse;
+
case KIF:
indent = source->lastindent;
lhs = makenode(&source->tok, NULL);
@@ -2109,15 +2189,19 @@ atom(Source *source, int flags) {
lhs->kind = AIF;
lhs->u.payload = expr(source, POR);
skipnewline(source);
+
if (getkind(source) == 'I' && source->tok.u.key == auxthen)
gettok(source, false);
+
lhs->lhs = stmtlist(source, indent, SSCOPE);
joinelse:
if (getkind(source) == KELSE && source->lastindent >= indent) {
gettok(source, false);
lhs->rhs = stmtlist(source, indent, SSCOPE);
}
+
break;
+
default:
joinerror:
error(getloc(source), "expected expression");
@@ -2156,6 +2240,7 @@ atom(Source *source, int flags) {
expect(source, ']', true, "expected ']'");
continue;
}
+
gettok(source, true);
}
@@ -2206,7 +2291,9 @@ expr(Source *source, int minprec) {
} else {
last = lhs;
}
+
break;
+
default:
last = NULL;
break;
@@ -2307,6 +2394,7 @@ isinttype(Type *ty) {
case TS32: case TU32:
case TS64: case TU64:
return true;
+
default:
return false;
}
@@ -2317,6 +2405,7 @@ isfloattype(Type *ty) {
switch (ty->kind) {
case TF32: case TF64:
return true;
+
default:
return false;
}
@@ -2333,6 +2422,7 @@ isarithtype(Type *ty) {
case TS64: case TU64:
case TF32: case TF64:
return true;
+
default:
return false;
}
@@ -2345,6 +2435,7 @@ isunsignedtype(Type *ty) {
case TU8: case TU16:
case TU32: case TU64:
return true;
+
default:
return false;
}
@@ -2356,12 +2447,14 @@ maskint(int size, uint64_t value) {
if (size == 1) return value & 0xfful;
if (size == 2) return value & 0xfffful;
if (size == 4) return value & 0xfffffffful;
+
return value;
}
double
maskfloat(int size, double value) {
if (size == 4) return (double) (float) value;
+
return value;
}
@@ -2371,6 +2464,7 @@ convint(int srcsize, bool srcsigned, uint64_t value) {
if (srcsize == 1) return (uint64_t) (int8_t ) value;
if (srcsize == 2) return (uint64_t) (int16_t) value;
if (srcsize == 4) return (uint64_t) (int32_t) value;
+
return value;
}
@@ -2451,6 +2545,7 @@ autoref(Type *ty, Node *node)
} else if (numderefs < -1) {
error(&node->loc, "double referencing");
/* TODO(m21c): ERROR: double referencing */
+
return node;
}
@@ -2477,6 +2572,7 @@ wrap(Type *ty, Node *node) {
ty->size,
node->u.d
);
+
} else if (isinttype(ty)) {
node->u.u = maskint(
ty->size,
@@ -2492,6 +2588,7 @@ wrap(Type *ty, Node *node) {
node->u.u
)
);
+
} else if (isinttype(ty)) {
node->u.u = maskint(
ty->size,
@@ -2514,6 +2611,7 @@ wrap(Type *ty, Node *node) {
node->kind = ACONV;
node->type = ty;
relinknodes(node, node->lhs);
+
return node;
}
@@ -2527,6 +2625,7 @@ conv(Node *node) {
return wrap(prim + TINT, node);
if (ty->kind == TUINFER)
return wrap(prim + TUINT, node);
+
return autoref(NULL, node);
}
@@ -2734,6 +2833,7 @@ typecheck(Env *env, Node *expr) {
case OASS:
c->type = lhs->type;
break;
+
case OMULA: case ODIVA: case OMODA:
case OADDA: case OSUBA:
if (isarithtype(lhs->type) &&
@@ -2748,7 +2848,9 @@ typecheck(Env *env, Node *expr) {
c->type = prim + TERRTYPE;
}
+
break;
+
case OLSHA: case ORSHA: case OARSHA:
case OANDA:
case OORA: case OXORA:
@@ -2764,6 +2866,7 @@ typecheck(Env *env, Node *expr) {
c->type = prim + TERRTYPE;
}
+
break;
}
@@ -2774,6 +2877,7 @@ typecheck(Env *env, Node *expr) {
case ADECL:
if (c->lhs)
c->lhs = wrap(c->type, typecheck(env, c->lhs));
+
break;
case ASCOPE:
@@ -2789,6 +2893,7 @@ typecheck(Env *env, Node *expr) {
assert(c->lhs);
c->lhs = typecheck(env, c->lhs);
c->lhs = conv(c->lhs);
+
break;
default:
@@ -2853,7 +2958,9 @@ foldexpr(Env *env, Node *expr) {
);
}
} while (0);
+
break;
+
case OADD: case OSUB:
if (lhs->kind == 'N' && rhs->kind == 'N') {
if (c->kind == OADD) evalbinary(+);
@@ -2871,7 +2978,9 @@ foldexpr(Env *env, Node *expr) {
*c = *lhs;
/* delete(lhs); delete(rhs) */
}
+
break;
+
case OMUL: case ODIV: case OMOD:
if (lhs->kind == 'N' && rhs->kind == 'N') {
if (c->kind == OMUL) {
@@ -2906,11 +3015,15 @@ foldexpr(Env *env, Node *expr) {
*c = *lhs;
/* delete(lhs); delete(rhs) */
}
+
break;
+
case OPLUS:
*c = *lhs;
+
/* delete(lhs) */
break;
+
case OMINUS:
if (lhs->kind == 'N') {
if (isfloattype(ty)) {
@@ -2926,7 +3039,9 @@ foldexpr(Env *env, Node *expr) {
*c = *lhs->lhs;
/* delete(lhs) */
}
+
break;
+
case OBAND: case OBOR: case OXOR:
if (lhs->kind == 'N' && rhs->kind == 'N') {
assert(
@@ -2950,14 +3065,19 @@ foldexpr(Env *env, Node *expr) {
c->kind = 'N';
c->u.u = maskint(ty->size, c->u.u);
}
+
break;
+
case ACONV:
/* TODO(m21c): implement this properly! */
lhs = foldexpr(env, lhs);
if (lhs->type->kind == c->type->kind)
*c = *lhs /*, delete(lhs) */;
+
+ break;
}
}
+
return expr;
}
@@ -3023,41 +3143,53 @@ highlight(FILE *out, Highlight kind) {
case HLDELIM:
n += fprintf(out, "\e[2m");
break;
+
case HLUNKNOWN:
n += fprintf(out, "\e[41;30m");
break;
+
case HLKEYWORD:
n += fprintf(out, "\e[35m");
break;
+
case HLNUMBER:
n += fprintf(out, "\e[36m");
break;
+
case HLSTRING:
n += fprintf(out, "\e[31m");
break;
+
case HLTYPE:
n += fprintf(out, "\e[34m");
break;
+
case HLFUNCTION:
n += fprintf(out, "\e[1;3m");
break;
+
case HLPARAM:
n += fprintf(out, "\e[3m");
break;
+
#if 0
case HLFUNCTIONDECL:
n += fprintf(out, "\e[1;4;3m");
break;
+
case HLPARAMDECL:
n += fprintf(out, "\e[4;3m");
break;
+
case HLDECL:
n += fprintf(out, "\e[4m");
break;
#endif
+
case HLINFO:
n += fprintf(out, "\e[33m");
break;
+
case HLPROMPT:
n += fprintf(out, "\e[35m");
break;
@@ -3085,8 +3217,10 @@ printtype(FILE *out, Type *type, int indent) {
n += printexpr(out, type->u.val, indent);
n += fprintf(out, "]");
break;
+
#define typecase(type, str) \
case type: n += fprintf(out, str); break
+
typecase(TERRTYPE, "<error-type>");
typecase(TUNDEFINED, "<undefined-type>");
typecase(TPTR, "*");
@@ -3097,6 +3231,7 @@ printtype(FILE *out, Type *type, int indent) {
typecase(TS32, "int" ); typecase(TU32, "uint" );
typecase(TS64, "s64" ); typecase(TU64, "u64" );
typecase(TF32, "float"); typecase(TF64, "double");
+
#undef typecase
default:;
}
@@ -3114,12 +3249,14 @@ printtypesuffix(FILE *out, Type *type, int indent) {
switch (type->kind) {
#define typecase(type, str) \
case type: n += fprintf(out, str); break
+
typecase(TINFER, "i" ); typecase(TUINFER, "u" );
typecase(TS8, "s8" ); typecase(TU8, "u8" );
typecase(TS16, "s16" ); typecase(TU16, "u16" );
typecase(TS32, "s32" ); typecase(TU32, "u32" );
typecase(TS64, "s64" ); typecase(TU64, "u64" );
typecase(TF32, "f32" ); typecase(TF64, "f64" );
+
#undef typecase
default:;
}
@@ -3168,24 +3305,31 @@ printstring(FILE *out, Node *string) {
case '\\':
n += fprintf(out, "\\\\");
break;
+
case '\n':
n += fprintf(out, "\\n");
break;
+
case '\r':
n += fprintf(out, "\\r");
break;
+
case '\t':
n += fprintf(out, "\\t");
break;
+
case '\"':
n += fprintf(out, "\\\"");
break;
+
case '\'':
n += fprintf(out, "\\\'");
break;
+
case 0:
n += fprintf(out, "\\0");
break;
+
default:
putc(str[i], out);
++n;
@@ -3305,11 +3449,13 @@ printexpr(FILE *out, Node *expr, int indent) {
n += highlight(out, HLDELIM);
n += fprintf(out, "%c", nodestrings[c->kind][1]);
break;
+
case ODISP:
n += highlight(out, HLDELIM);
n += fprintf(out, ".");
n += printexpr(out, c->rhs, indent);
break;
+
default:
n += highlight(out, HLDELIM);
n += fprintf(out, "%s", nodestrings[c->kind]);
@@ -3324,6 +3470,7 @@ printexpr(FILE *out, Node *expr, int indent) {
n += highlight(out, HLDELIM);
putc(')', out), ++n;
break;
+
default:
n += highlight(out, HLDELIM);
n += fprintf(out, "%s", nodestrings[c->kind]);
@@ -3343,6 +3490,7 @@ printexpr(FILE *out, Node *expr, int indent) {
n += fprintf(out, "%s?", getstring(idents, c->u.key));
n += highlight(out, HLNONE);
break;
+
case 'N':
n += highlight(out, HLNUMBER);
if (c->type->kind == TFLOAT ||
@@ -3355,10 +3503,12 @@ printexpr(FILE *out, Node *expr, int indent) {
n += fprintf(out, "%lu", c->u.u);
n += printtypesuffix(out, c->type, indent);
break;
+
case 'S':
n += highlight(out, HLSTRING);
n += printstring(out, c);
break;
+
case ADECLREF:
n += highlight(out,
c->u.declref->kind == DFUNCTION ? HLFUNCTION :
@@ -3366,22 +3516,27 @@ printexpr(FILE *out, Node *expr, int indent) {
HLIDENT);
n += fprintf(out, "%s", getstring(idents, c->u.declref->key));
break;
+
case ADECL:
n += printdeclaration(out, c->u.declref, indent);
break;
+
case ARETURN:
n += highlight(out, HLKEYWORD);
n += fprintf(out, "return ");
n += printexpr(out, c->rhs, indent);
break;
+
case ABREAK:
n += highlight(out, HLKEYWORD);
n += fprintf(out, "break");
break;
+
case ACONTINUE:
n += highlight(out, HLKEYWORD);
n += fprintf(out, "continue");
break;
+
case AIF:
n += highlight(out, HLKEYWORD);
n += fprintf(out, "if ");
@@ -3397,18 +3552,23 @@ printexpr(FILE *out, Node *expr, int indent) {
n += fprintf(out, "else");
n += printclause(out, c->rhs, indent);
}
+
break;
+
case ADO:
n += highlight(out, HLKEYWORD);
n += fprintf(out, "do");
n += printclause(out, c->lhs, indent);
break;
+
case ASTMT:
n += printexpr(out, c->lhs, indent);
break;
+
case ASCOPE:
n += printexpr(out, c->lhs, indent);
break;
+
case ACONV:
n += highlight(out, HLDELIM);
n += fprintf(out, "conv(");
@@ -3418,6 +3578,7 @@ printexpr(FILE *out, Node *expr, int indent) {
n += fprintf(out, ") ");
n += printoperant(out, c->lhs, PUNARY, false, indent);
break;
+
case AADDR:
n += highlight(out, HLDELIM);
n += fputs("&{", out);
@@ -3425,6 +3586,7 @@ printexpr(FILE *out, Node *expr, int indent) {
n += highlight(out, HLDELIM);
n += fputs("}", out);
break;
+
case ADEREF:
n += highlight(out, HLDELIM);
n += fputs("*{", out);
@@ -3432,6 +3594,7 @@ printexpr(FILE *out, Node *expr, int indent) {
n += highlight(out, HLDELIM);
n += fputs("}", out);
break;
+
default:
break;
}