combined some awk options into QSE_AWK_EXTRAKWS.

deleted QSE_AWK_EXTRAOPS and enabled all new operators by default
added === and !==.
fixed a bug in printing the explicit concatenation operator(%%, %%=)
improved @include handling
This commit is contained in:
hyung-hwan 2012-10-25 14:38:27 +00:00
parent b53fe11c04
commit 8ac0963885
16 changed files with 342 additions and 273 deletions

View File

@ -382,23 +382,19 @@ struct opttab_t
{
{ QSE_T("implicit"), QSE_AWK_IMPLICIT, QSE_T("allow undeclared variables") },
{ QSE_T("explicit"), QSE_AWK_EXPLICIT, QSE_T("allow declared variables(local,global)") },
{ QSE_T("extraops"), QSE_AWK_EXTRAOPS, QSE_T("enable extra operators(<<,>>,^^,\\)") },
{ QSE_T("extrakws"), QSE_AWK_EXTRAKWS, QSE_T("enable abort,reset,nextofile,OFILENAME,@include") },
{ QSE_T("rio"), QSE_AWK_RIO, QSE_T("enable builtin I/O including getline & print") },
{ QSE_T("rwpipe"), QSE_AWK_RWPIPE, QSE_T("allow a dual-directional pipe") },
{ QSE_T("newline"), QSE_AWK_NEWLINE, QSE_T("enable a newline to terminate a statement") },
{ QSE_T("striprecspc"), QSE_AWK_STRIPRECSPC, QSE_T("strip spaces in splitting a record") },
{ QSE_T("stripstrspc"), QSE_AWK_STRIPSTRSPC, QSE_T("strip spaces in string-to-number conversion") },
{ QSE_T("nextofile"), QSE_AWK_NEXTOFILE, QSE_T("enable 'nextofile'") },
{ QSE_T("reset"), QSE_AWK_RESET, QSE_T("enable 'reset'") },
{ QSE_T("crlf"), QSE_AWK_CRLF, QSE_T("use CRLF for a newline") },
{ QSE_T("maptovar"), QSE_AWK_MAPTOVAR, QSE_T("allow a map to be assigned or returned") },
{ QSE_T("pablock"), QSE_AWK_PABLOCK, QSE_T("enable pattern-action loop") },
{ QSE_T("rexbound"), QSE_AWK_REXBOUND, QSE_T("enable {n,m} in a regular expression") },
{ QSE_T("ncmponstr"), QSE_AWK_NCMPONSTR, QSE_T("perform numeric comparsion on numeric strings") },
{ QSE_T("strictnaming"), QSE_AWK_STRICTNAMING, QSE_T("enable the strict naming rule") },
{ QSE_T("include"), QSE_AWK_INCLUDE, QSE_T("enable '@include'") },
{ QSE_T("tolerant"), QSE_AWK_TOLERANT, QSE_T("make more fault-tolerant") },
{ QSE_T("abort"), QSE_AWK_ABORT, QSE_T("enable 'abort'") },
{ QSE_NULL, 0, QSE_NULL }
};
@ -525,23 +521,19 @@ static int comparg (int argc, qse_char_t* argv[], struct arg_t* arg)
{
{ QSE_T(":implicit"), QSE_T('\0') },
{ QSE_T(":explicit"), QSE_T('\0') },
{ QSE_T(":extraops"), QSE_T('\0') },
{ QSE_T(":extrakws"), QSE_T('\0') },
{ QSE_T(":rio"), QSE_T('\0') },
{ QSE_T(":rwpipe"), QSE_T('\0') },
{ QSE_T(":newline"), QSE_T('\0') },
{ QSE_T(":striprecspc"), QSE_T('\0') },
{ QSE_T(":stripstrspc"), QSE_T('\0') },
{ QSE_T(":nextofile"), QSE_T('\0') },
{ QSE_T(":reset"), QSE_T('\0') },
{ QSE_T(":crlf"), QSE_T('\0') },
{ QSE_T(":maptovar"), QSE_T('\0') },
{ QSE_T(":pablock"), QSE_T('\0') },
{ QSE_T(":rexbound"), QSE_T('\0') },
{ QSE_T(":ncmponstr"), QSE_T('\0') },
{ QSE_T(":strictnaming"), QSE_T('\0') },
{ QSE_T(":include"), QSE_T('\0') },
{ QSE_T(":tolerant"), QSE_T('\0') },
{ QSE_T(":abort"), QSE_T('\0') },
{ QSE_T(":call"), QSE_T('c') },
{ QSE_T(":file"), QSE_T('f') },

View File

@ -3,7 +3,8 @@
@section awk_content CONTENTS
- @ref awk_intro "INTRODUCTION"
- @ref awk_lang "AWK LANGUAGE"
- @ref awk_ext "AWK LANGUAGE EXTENSIONS"
- @ref awk_litvar "LITERAL AND VARIABLE"
- @ref awk_ext_teq "TEQ OPERATOR"
- @ref awk_ext_vardecl "VARIABLE DECLARATION"
- @ref awk_ext_include "INCLUDE"
- @ref awk_ext_print "EXTENDED PRINT/PRINTF"
@ -255,9 +256,74 @@ AWK has the following statement constructs.
- printf
- expression
@section awk_ext AWK LANGUAGE EXTENSIONS
Some language extensions are implemented and those can be enabled by setting
the corresponding options.
@subsection awk_litvar LITERAL AND VARIABLE
Value type
- Scalar
-- String
-- Integer
-- Floating-Pointer number
- Hashed Map
- Regular expression
Scalar values are immutable while a hashed map value is mutable.
A regular expression value is specially treated.
A variable is tied to a value when it is assigned with a value.
If the variable is tied to a map value, it can't be assigned again.
You can use 'reset' to untie the variable from the value, and thus
restore the variable to the 'nil' state.
....
@subsection awk_ext_teq TEQ OPERATOR
The === operator compares two values and evaluates to a non-zero value
if both have the same internal type and the actual values are the same.
so 1 is not equal to 1.0 for the === operator.
A map comparison for the === operator is a bit special. The contents of
the map is never inspected. Comparing two maps always result in inequality.
However, if two variables points to the same map value, it can evaluate
to a non-zero value. This is possible if you allow assigning a map to
another non-map variable with #QSE_AWK_MAPTOVAR. In this case, a map
is not deep-copied but the reference to it is copied.
@code
BEGIN {
a[10]=20;
b=a;
b[20]=40;
for (i in a) print i, a[i];
print a===b;
}
@endcode
The === operator may be also useful when you want to indicate an error
with an uninitialized variable. The following code check if the function
returned a map. Since the variable 'nil' has never been assigned, its
internal type is 'NIL' and
@code
function a ()
{
x[10] = 2;
return x;
}
BEGIN {
t = a();
if (t === nil)
print "nil";
else
print "ok";
}
@endcode.
The !== operator is a negated form of the === operator.
@subsection awk_ext_vardecl VARIABLE DECLARATION
@ -303,6 +369,16 @@ blocks appear. To use \@include, you must turn on #QSE_AWK_INCLUDE.
BEGIN { func_in_abc (); }
@endcode
A semicolon is optional after the included file name. The following is the
same as the sample above.
@code
@include "abc.awk";
BEGIN { func_in_abc(); }
@endcode
If #QSE_AWK_NEWLINE is off, the semicolon is required.
@subsection awk_ext_print EXTENDED PRINT/PRINTF
When #QSE_AWK_TOLERANT is on, print and printf are treated as if
they are function calls. In this mode, they return a negative number

View File

@ -460,6 +460,7 @@ struct qse_awk_sio_lxc_t
};
typedef struct qse_awk_sio_lxc_t qse_awk_sio_lxc_t;
typedef struct qse_awk_sio_arg_t qse_awk_sio_arg_t;
struct qse_awk_sio_arg_t
{
const qse_char_t* name; /**< [IN] name of I/O object */
@ -477,9 +478,8 @@ struct qse_awk_sio_arg_t
qse_size_t colm;
qse_awk_sio_lxc_t last;
struct qse_awk_sio_arg_t* next;
qse_awk_sio_arg_t* next;
};
typedef struct qse_awk_sio_arg_t qse_awk_sio_arg_t;
/**
* The qse_awk_sio_impl_t type defines a source IO function
@ -892,23 +892,18 @@ enum qse_awk_trait_t
/**
* allows undeclared variables and implicit concatenation
**/
QSE_AWK_IMPLICIT = (1 << 0),
QSE_AWK_IMPLICIT = (1 << 0),
/**
* allows explicit variable declaration, the concatenation
* operator, a period, and performs the parse-time function check.
*/
QSE_AWK_EXPLICIT = (1 << 1),
QSE_AWK_EXPLICIT = (1 << 1),
/**
* supports extra operators:
* - @b <<, <<= left-shift
* - @b >>, >>= right-shiftt
* - @b ^^, ^^= xor
* - @b ~ bitwise-not
* - @b // idiv (get quotient)
* enable abort,reset,nextofile,OFILENAME,@include.
*/
QSE_AWK_EXTRAOPS = (1 << 2),
QSE_AWK_EXTRAKWS = (1 << 2),
/** supports @b getline and @b print */
QSE_AWK_RIO = (1 << 3),
@ -951,12 +946,6 @@ enum qse_awk_trait_t
*/
QSE_AWK_STRIPSTRSPC = (1 << 7),
/** enables @b nextofile */
QSE_AWK_NEXTOFILE = (1 << 8),
/** enables @b reset */
QSE_AWK_RESET = (1 << 9),
/** CR + LF by default */
QSE_AWK_CRLF = (1 << 10),
@ -1005,9 +994,6 @@ enum qse_awk_trait_t
*/
QSE_AWK_TOLERANT = (1 << 17),
/** enables @b abort */
QSE_AWK_ABORT = (1 << 18),
/**
* makes #qse_awk_t to behave compatibly with classical AWK
* implementations
@ -1112,18 +1098,18 @@ enum qse_awk_errnum_t
QSE_AWK_EARGTF, /**< too few arguments */
QSE_AWK_EARGTM, /**< too many arguments */
QSE_AWK_EFUNNF, /**< function '${0}' not found */
QSE_AWK_ENOTIDX, /**< variable not indexable */
QSE_AWK_ENOTDEL, /**< variable '${0}' not deletable */
QSE_AWK_ENOTIDX, /**< not indexable */
QSE_AWK_ENOTDEL, /**< '${0}' not deletable */
QSE_AWK_ENOTMAP, /**< value not a map */
QSE_AWK_ENOTMAPIN, /**< right-hand side of 'in' not a map */
QSE_AWK_ENOTMAPNILIN, /**< right-hand side of 'in' not a map nor nil */
QSE_AWK_ENOTREF, /**< value not referenceable */
QSE_AWK_ENOTASS, /**< value not assignable */
QSE_AWK_EIDXVALASSMAP, /**< an indexed value cannot be assigned a map */
QSE_AWK_EPOSVALASSMAP, /**< a positional cannot be assigned a map */
QSE_AWK_EMAPTOSCALAR, /**< map '${0}' not assignable with a scalar */
QSE_AWK_EIDXVALASSMAP, /**< indexed value cannot be assigned a map */
QSE_AWK_EPOSVALASSMAP, /**< positional cannot be assigned a map */
QSE_AWK_EMAPNA, /**< map '${0}' not assignable */
QSE_AWK_EMAPPH, /**< map prohibited */
QSE_AWK_ESCALARTOMAP, /**< cannot change a scalar value to a map */
QSE_AWK_EMAPNA, /**< map not allowed */
QSE_AWK_EVALTYPE, /**< invalid value type */
QSE_AWK_ERNEXTBEG, /**< 'next' called from BEGIN block */
QSE_AWK_ERNEXTEND, /**< 'next' called from END block */

View File

@ -109,8 +109,8 @@ const qse_char_t* qse_awk_dflerrstr (const qse_awk_t* awk, qse_awk_errnum_t errn
QSE_T("too few arguments"),
QSE_T("too many arguments"),
QSE_T("function '${0}' not found"),
QSE_T("variable not indexable"),
QSE_T("variable '${0}' not deletable"),
QSE_T("not indexable"),
QSE_T("'${0}' not deletable"),
QSE_T("value not a map"),
QSE_T("right-hand side of the 'in' operator not a map"),
QSE_T("right-hand side of the 'in' operator not a map nor nil"),
@ -118,9 +118,9 @@ const qse_char_t* qse_awk_dflerrstr (const qse_awk_t* awk, qse_awk_errnum_t errn
QSE_T("value not assignable"),
QSE_T("indexed value cannot be assigned a map"),
QSE_T("positional value cannot be assigned a map"),
QSE_T("map '${0}' not assignable with a scalar"),
QSE_T("map '${0}' not assignable"),
QSE_T("map prohibited"),
QSE_T("cannot change a scalar value to a map"),
QSE_T("map not allowed"),
QSE_T("invalid value type"),
QSE_T("'next' called from BEGIN block"),
QSE_T("'next' called from END block"),

View File

@ -652,9 +652,12 @@ static int fnc_split (qse_awk_rtx_t* run, const qse_awk_fnc_info_t* fi)
if ((*a1_ref)->type != QSE_AWK_VAL_NIL &&
(*a1_ref)->type != QSE_AWK_VAL_MAP)
{
/* cannot change a scalar value to a map */
qse_awk_rtx_seterrnum (run, QSE_AWK_ESCALARTOMAP, QSE_NULL);
return -1;
if (!(run->awk->opt.trait & QSE_AWK_MAPTOVAR))
{
/* cannot change a scalar value to a map */
qse_awk_rtx_seterrnum (run, QSE_AWK_ESCALARTOMAP, QSE_NULL);
return -1;
}
}
if (a0->type == QSE_AWK_VAL_STR)
@ -976,7 +979,7 @@ static int __substitute (qse_awk_rtx_t* run, qse_long_t max_count)
if ((*a2_ref)->type == QSE_AWK_VAL_MAP)
{
/* a map is not allowed as the third parameter */
qse_awk_rtx_seterrnum (run, QSE_AWK_EMAPNA, QSE_NULL);
qse_awk_rtx_seterrnum (run, QSE_AWK_EMAPPH, QSE_NULL);
goto oops;
}

View File

@ -28,8 +28,8 @@ enum tok_t
/* special token to direct the parser to include a file specified */
TOK_INCLUDE,
/* TOK_XXX_ASSNs should be in sync
* with assop in assign_to_opcode */
/* TOK_XXX_ASSNs should be in sync with assop in assign_to_opcode.
* it also should be in the order as qse_awk_assop_type_t in run.h */
TOK_ASSN,
TOK_PLUS_ASSN,
TOK_MINUS_ASSN,
@ -46,12 +46,15 @@ enum tok_t
TOK_BOR_ASSN,
/* end of TOK_XXX_ASSN */
TOK_TEQ,
TOK_TNE,
TOK_EQ,
TOK_NE,
TOK_LE,
TOK_LT,
TOK_GE,
TOK_GT,
TOK_MA, /* match */
TOK_NM, /* not match */
TOK_LNOT, /* logical negation ! */
TOK_PLUS,
@ -67,7 +70,7 @@ enum tok_t
TOK_BOR,
TOK_BXOR,
TOK_BAND,
TOK_TILDE, /* used for unary bitwise-not and regex match */
TOK_BNOT, /* used for unary bitwise-not and regex match */
TOK_RS,
TOK_LS,
TOK_IN,
@ -259,7 +262,7 @@ static kwent_t kwtab[] =
* also keep it sorted by the first field for binary search */
{ { QSE_T("BEGIN"), 5 }, TOK_BEGIN, QSE_AWK_PABLOCK },
{ { QSE_T("END"), 3 }, TOK_END, QSE_AWK_PABLOCK },
{ { QSE_T("abort"), 5 }, TOK_ABORT, QSE_AWK_ABORT },
{ { QSE_T("abort"), 5 }, TOK_ABORT, QSE_AWK_EXTRAKWS },
{ { QSE_T("break"), 5 }, TOK_BREAK, 0 },
{ { QSE_T("continue"), 8 }, TOK_CONTINUE, 0 },
{ { QSE_T("delete"), 6 }, TOK_DELETE, 0 },
@ -272,14 +275,14 @@ static kwent_t kwtab[] =
{ { QSE_T("global"), 6 }, TOK_GLOBAL, QSE_AWK_EXPLICIT },
{ { QSE_T("if"), 2 }, TOK_IF, 0 },
{ { QSE_T("in"), 2 }, TOK_IN, 0 },
{ { QSE_T("include"), 7 }, TOK_INCLUDE, QSE_AWK_INCLUDE },
{ { QSE_T("include"), 7 }, TOK_INCLUDE, QSE_AWK_EXTRAKWS },
{ { QSE_T("local"), 5 }, TOK_LOCAL, QSE_AWK_EXPLICIT },
{ { QSE_T("next"), 4 }, TOK_NEXT, QSE_AWK_PABLOCK },
{ { QSE_T("nextfile"), 8 }, TOK_NEXTFILE, QSE_AWK_PABLOCK },
{ { QSE_T("nextofile"), 9 }, TOK_NEXTOFILE, QSE_AWK_PABLOCK | QSE_AWK_NEXTOFILE },
{ { QSE_T("nextofile"), 9 }, TOK_NEXTOFILE, QSE_AWK_PABLOCK | QSE_AWK_EXTRAKWS },
{ { QSE_T("print"), 5 }, TOK_PRINT, QSE_AWK_RIO },
{ { QSE_T("printf"), 6 }, TOK_PRINTF, QSE_AWK_RIO },
{ { QSE_T("reset"), 5 }, TOK_RESET, QSE_AWK_RESET },
{ { QSE_T("reset"), 5 }, TOK_RESET, QSE_AWK_EXTRAKWS },
{ { QSE_T("return"), 6 }, TOK_RETURN, 0 },
{ { QSE_T("while"), 5 }, TOK_WHILE, 0 }
};
@ -319,7 +322,7 @@ static global_t gtab[] =
{ QSE_T("NR"), 2, QSE_AWK_PABLOCK },
/* current output file name */
{ QSE_T("OFILENAME"), 9, QSE_AWK_PABLOCK | QSE_AWK_NEXTOFILE },
{ QSE_T("OFILENAME"), 9, QSE_AWK_PABLOCK | QSE_AWK_EXTRAKWS },
/* output real-to-str conversion format for 'print' */
{ QSE_T("OFMT"), 4, QSE_AWK_RIO },
@ -385,12 +388,7 @@ static global_t gtab[] =
qse_awk_seterror (awk, QSE_AWK_ENOERR, QSE_NULL, QSE_NULL)
#define SETERR_TOK(awk,code) \
do { \
qse_cstr_t __ea; \
__ea.len = QSE_STR_LEN((awk)->tok.name); \
__ea.ptr = QSE_STR_PTR((awk)->tok.name); \
qse_awk_seterror (awk, code, &__ea, &(awk)->tok.loc); \
} while (0)
qse_awk_seterror (awk, code, QSE_STR_CSTR((awk)->tok.name), &(awk)->tok.loc)
#define SETERR_COD(awk,code) \
qse_awk_seterror (awk, code, QSE_NULL, QSE_NULL)
@ -673,6 +671,46 @@ int qse_awk_parse (qse_awk_t* awk, qse_awk_sio_t* sio)
return n;
}
static int end_include (qse_awk_t* awk)
{
int x;
qse_awk_sio_arg_t* cur;
if (awk->sio.inp == &awk->sio.arg) return 0; /* no include */
/* if it is an included file, close it and
* retry to read a character from an outer file */
CLRERR (awk);
x = awk->sio.inf (
awk, QSE_AWK_SIO_CLOSE,
awk->sio.inp, QSE_NULL, 0);
/* if closing has failed, still destroy the
* sio structure first as normal and return
* the failure below. this way, the caller
* does not call QSE_AWK_SIO_CLOSE on
* awk->sio.inp again. */
cur = awk->sio.inp;
awk->sio.inp = awk->sio.inp->next;
QSE_ASSERT (cur->name != QSE_NULL);
QSE_MMGR_FREE (awk->mmgr, cur);
awk->parse.depth.incl--;
if (x != 0)
{
/* the failure mentioned above is returned here */
if (ISNOERR(awk))
SETERR_ARG (awk, QSE_AWK_ECLOSE, QSE_T("<SIN>"), 5);
return -1;
}
awk->sio.last = awk->sio.inp->last;
return 1; /* ended the included file successfully */
}
static int begin_include (qse_awk_t* awk)
{
qse_ssize_t op;
@ -747,50 +785,21 @@ static int begin_include (qse_awk_t* awk)
awk->sio.inp->line = 1;
awk->sio.inp->colm = 1;
return 0;
oops:
if (arg != QSE_NULL) QSE_MMGR_FREE (awk->mmgr, arg);
return -1;
}
static int end_include (qse_awk_t* awk)
{
int x;
qse_awk_sio_arg_t* cur;
if (awk->sio.inp == &awk->sio.arg) return 0; /* no include */
/* if it is an included file, close it and
* retry to read a character from an outer file */
CLRERR (awk);
x = awk->sio.inf (
awk, QSE_AWK_SIO_CLOSE,
awk->sio.inp, QSE_NULL, 0);
/* if closing has failed, still destroy the
* sio structure first as normal and return
* the failure below. this way, the caller
* does not call QSE_AWK_SIO_CLOSE on
* awk->sio.inp again. */
cur = awk->sio.inp;
awk->sio.inp = awk->sio.inp->next;
QSE_ASSERT (cur->name != QSE_NULL);
QSE_MMGR_FREE (awk->mmgr, cur);
awk->parse.depth.incl--;
if (x != 0)
/* read in the first character in the included file.
* so the next call to get_token() sees the character read
* from this file. */
if (get_char (awk) <= -1)
{
/* the failure mentioned above is returned here */
if (ISNOERR(awk))
SETERR_ARG (awk, QSE_AWK_ECLOSE, QSE_T("<SIN>"), 5);
end_include (awk);
/* since i've called end_include(), i don't go to oops */
return -1;
}
return 1; /* ended the included file successfully */
return 0;
oops:
if (arg) QSE_MMGR_FREE (awk->mmgr, arg);
return -1;
}
static qse_awk_t* parse_progunit (qse_awk_t* awk)
@ -850,8 +859,9 @@ retry:
if (begin_include (awk) <= -1) return QSE_NULL;
/* read the first meaningful token from the included file
* and recheck it by jumping to retry: */
/* i'm retrying to get the first top-level
* element as if parse_progunit() is called.
* so i need to skip NEWLINE tokens */
do
{
if (get_token(awk) <= -1) return QSE_NULL;
@ -898,6 +908,10 @@ retry:
awk->parse.id.block = PARSE_BEGIN_BLOCK;
if (parse_begin (awk) == QSE_NULL) return QSE_NULL;
/* skip a semicolon after an action block if any */
if (MATCH(awk,TOK_SEMICOLON) &&
get_token (awk) <= -1) return QSE_NULL;
}
else if (MATCH(awk,TOK_END))
{
@ -926,6 +940,10 @@ retry:
awk->parse.id.block = PARSE_END_BLOCK;
if (parse_end (awk) == QSE_NULL) return QSE_NULL;
/* skip a semicolon after an action block if any */
if (MATCH(awk,TOK_SEMICOLON) &&
get_token (awk) <= -1) return QSE_NULL;
}
else if (MATCH(awk,TOK_LBRACE))
{
@ -3629,8 +3647,7 @@ oops:
return QSE_NULL;
}
static qse_awk_nde_t* parse_logical_or (
qse_awk_t* awk, const qse_awk_loc_t* xloc)
static qse_awk_nde_t* parse_logical_or (qse_awk_t* awk, const qse_awk_loc_t* xloc)
{
static binmap_t map[] =
{
@ -3641,8 +3658,7 @@ static qse_awk_nde_t* parse_logical_or (
return parse_binary (awk, xloc, 1, map, parse_logical_and);
}
static qse_awk_nde_t* parse_logical_and (
qse_awk_t* awk, const qse_awk_loc_t* xloc)
static qse_awk_nde_t* parse_logical_and (qse_awk_t* awk, const qse_awk_loc_t* xloc)
{
static binmap_t map[] =
{
@ -3653,8 +3669,7 @@ static qse_awk_nde_t* parse_logical_and (
return parse_binary (awk, xloc, 1, map, parse_in);
}
static qse_awk_nde_t* parse_in (
qse_awk_t* awk, const qse_awk_loc_t* xloc)
static qse_awk_nde_t* parse_in (qse_awk_t* awk, const qse_awk_loc_t* xloc)
{
/*
static binmap_t map[] =
@ -3708,21 +3723,19 @@ oops:
return QSE_NULL;
}
static qse_awk_nde_t* parse_regex_match (
qse_awk_t* awk, const qse_awk_loc_t* xloc)
static qse_awk_nde_t* parse_regex_match (qse_awk_t* awk, const qse_awk_loc_t* xloc)
{
static binmap_t map[] =
{
{ TOK_TILDE, QSE_AWK_BINOP_MA },
{ TOK_NM, QSE_AWK_BINOP_NM },
{ TOK_EOF, 0 },
{ TOK_MA, QSE_AWK_BINOP_MA },
{ TOK_NM, QSE_AWK_BINOP_NM },
{ TOK_EOF, 0 },
};
return parse_binary (awk, xloc, 0, map, parse_bitwise_or);
}
static qse_awk_nde_t* parse_bitwise_or (
qse_awk_t* awk, const qse_awk_loc_t* xloc)
static qse_awk_nde_t* parse_bitwise_or (qse_awk_t* awk, const qse_awk_loc_t* xloc)
{
static binmap_t map[] =
{
@ -3733,8 +3746,7 @@ static qse_awk_nde_t* parse_bitwise_or (
return parse_binary (awk, xloc, 0, map, parse_bitwise_xor);
}
static qse_awk_nde_t* parse_bitwise_xor (
qse_awk_t* awk, const qse_awk_loc_t* xloc)
static qse_awk_nde_t* parse_bitwise_xor (qse_awk_t* awk, const qse_awk_loc_t* xloc)
{
static binmap_t map[] =
{
@ -3745,8 +3757,7 @@ static qse_awk_nde_t* parse_bitwise_xor (
return parse_binary (awk, xloc, 0, map, parse_bitwise_and);
}
static qse_awk_nde_t* parse_bitwise_and (
qse_awk_t* awk, const qse_awk_loc_t* xloc)
static qse_awk_nde_t* parse_bitwise_and (qse_awk_t* awk, const qse_awk_loc_t* xloc)
{
static binmap_t map[] =
{
@ -3757,11 +3768,12 @@ static qse_awk_nde_t* parse_bitwise_and (
return parse_binary (awk, xloc, 0, map, parse_equality);
}
static qse_awk_nde_t* parse_equality (
qse_awk_t* awk, const qse_awk_loc_t* xloc)
static qse_awk_nde_t* parse_equality (qse_awk_t* awk, const qse_awk_loc_t* xloc)
{
static binmap_t map[] =
{
{ TOK_TEQ, QSE_AWK_BINOP_TEQ },
{ TOK_TNE, QSE_AWK_BINOP_TNE },
{ TOK_EQ, QSE_AWK_BINOP_EQ },
{ TOK_NE, QSE_AWK_BINOP_NE },
{ TOK_EOF, 0 }
@ -3770,8 +3782,7 @@ static qse_awk_nde_t* parse_equality (
return parse_binary (awk, xloc, 0, map, parse_relational);
}
static qse_awk_nde_t* parse_relational (
qse_awk_t* awk, const qse_awk_loc_t* xloc)
static qse_awk_nde_t* parse_relational (qse_awk_t* awk, const qse_awk_loc_t* xloc)
{
static binmap_t map[] =
{
@ -3782,12 +3793,10 @@ static qse_awk_nde_t* parse_relational (
{ TOK_EOF, 0 }
};
return parse_binary (awk, xloc, 0, map,
((awk->opt.trait & QSE_AWK_EXTRAOPS)? parse_shift: parse_concat));
return parse_binary (awk, xloc, 0, map, parse_shift);
}
static qse_awk_nde_t* parse_shift (
qse_awk_t* awk, const qse_awk_loc_t* xloc)
static qse_awk_nde_t* parse_shift (qse_awk_t* awk, const qse_awk_loc_t* xloc)
{
static binmap_t map[] =
{
@ -3799,8 +3808,7 @@ static qse_awk_nde_t* parse_shift (
return parse_binary (awk, xloc, 0, map, parse_concat);
}
static qse_awk_nde_t* parse_concat (
qse_awk_t* awk, const qse_awk_loc_t* xloc)
static qse_awk_nde_t* parse_concat (qse_awk_t* awk, const qse_awk_loc_t* xloc)
{
qse_awk_nde_t* left = QSE_NULL;
qse_awk_nde_t* right = QSE_NULL;
@ -3853,8 +3861,7 @@ oops:
return QSE_NULL;
}
static qse_awk_nde_t* parse_additive (
qse_awk_t* awk, const qse_awk_loc_t* xloc)
static qse_awk_nde_t* parse_additive (qse_awk_t* awk, const qse_awk_loc_t* xloc)
{
static binmap_t map[] =
{
@ -3866,8 +3873,7 @@ static qse_awk_nde_t* parse_additive (
return parse_binary (awk, xloc, 0, map, parse_multiplicative);
}
static qse_awk_nde_t* parse_multiplicative (
qse_awk_t* awk, const qse_awk_loc_t* xloc)
static qse_awk_nde_t* parse_multiplicative (qse_awk_t* awk, const qse_awk_loc_t* xloc)
{
static binmap_t map[] =
{
@ -3882,8 +3888,7 @@ static qse_awk_nde_t* parse_multiplicative (
return parse_binary (awk, xloc, 0, map, parse_unary);
}
static qse_awk_nde_t* parse_unary (
qse_awk_t* awk, const qse_awk_loc_t* xloc)
static qse_awk_nde_t* parse_unary (qse_awk_t* awk, const qse_awk_loc_t* xloc)
{
qse_awk_nde_t* left;
qse_awk_loc_t uloc;
@ -3894,8 +3899,7 @@ static qse_awk_nde_t* parse_unary (
opcode = (MATCH(awk,TOK_PLUS))? QSE_AWK_UNROP_PLUS:
(MATCH(awk,TOK_MINUS))? QSE_AWK_UNROP_MINUS:
(MATCH(awk,TOK_LNOT))? QSE_AWK_UNROP_LNOT:
((awk->opt.trait & QSE_AWK_EXTRAOPS) && MATCH(awk,TOK_TILDE))?
QSE_AWK_UNROP_BNOT: -1;
(MATCH(awk,TOK_BNOT))? QSE_AWK_UNROP_BNOT: -1;
/*if (opcode <= -1) return parse_increment (awk);*/
if (opcode <= -1) return parse_exponent (awk, xloc);
@ -4023,8 +4027,7 @@ static qse_awk_nde_t* parse_unary (
}
}
static qse_awk_nde_t* parse_exponent (
qse_awk_t* awk, const qse_awk_loc_t* xloc)
static qse_awk_nde_t* parse_exponent (qse_awk_t* awk, const qse_awk_loc_t* xloc)
{
static binmap_t map[] =
{
@ -4035,8 +4038,7 @@ static qse_awk_nde_t* parse_exponent (
return parse_binary (awk, xloc, 0, map, parse_unary_exp);
}
static qse_awk_nde_t* parse_unary_exp (
qse_awk_t* awk, const qse_awk_loc_t* xloc)
static qse_awk_nde_t* parse_unary_exp (qse_awk_t* awk, const qse_awk_loc_t* xloc)
{
qse_awk_nde_exp_t* nde;
qse_awk_nde_t* left;
@ -4046,8 +4048,7 @@ static qse_awk_nde_t* parse_unary_exp (
opcode = (MATCH(awk,TOK_PLUS))? QSE_AWK_UNROP_PLUS:
(MATCH(awk,TOK_MINUS))? QSE_AWK_UNROP_MINUS:
(MATCH(awk,TOK_LNOT))? QSE_AWK_UNROP_LNOT:
((awk->opt.trait & QSE_AWK_EXTRAOPS) && MATCH(awk,TOK_TILDE))?
QSE_AWK_UNROP_BNOT: -1;
(MATCH(awk,TOK_BNOT))? QSE_AWK_UNROP_BNOT: -1;
if (opcode <= -1) return parse_increment (awk, xloc);
@ -4085,8 +4086,7 @@ static qse_awk_nde_t* parse_unary_exp (
return (qse_awk_nde_t*)nde;
}
static qse_awk_nde_t* parse_increment (
qse_awk_t* awk, const qse_awk_loc_t* xloc)
static qse_awk_nde_t* parse_increment (qse_awk_t* awk, const qse_awk_loc_t* xloc)
{
qse_awk_nde_exp_t* nde;
qse_awk_nde_t* left;
@ -5805,16 +5805,18 @@ static int get_symbols (qse_awk_t* awk, qse_cint_t c, qse_awk_tok_t* tok)
static struct ops_t ops[] =
{
{ QSE_T("==="), 3, TOK_TEQ, 0 },
{ QSE_T("=="), 2, TOK_EQ, 0 },
{ QSE_T("="), 1, TOK_ASSN, 0 },
{ QSE_T("!=="), 3, TOK_TNE, 0 },
{ QSE_T("!="), 2, TOK_NE, 0 },
{ QSE_T("!~"), 2, TOK_NM, 0 },
{ QSE_T("!"), 1, TOK_LNOT, 0 },
{ QSE_T(">>="), 3, TOK_RS_ASSN, QSE_AWK_EXTRAOPS },
{ QSE_T(">>="), 3, TOK_RS_ASSN, 0 },
{ QSE_T(">>"), 2, TOK_RS, 0 },
{ QSE_T(">="), 2, TOK_GE, 0 },
{ QSE_T(">"), 1, TOK_GT, 0 },
{ QSE_T("<<="), 3, TOK_LS_ASSN, QSE_AWK_EXTRAOPS },
{ QSE_T("<<="), 3, TOK_LS_ASSN, 0 },
{ QSE_T("<<"), 2, TOK_LS, 0 },
{ QSE_T("<="), 2, TOK_LE, 0 },
{ QSE_T("<"), 1, TOK_LT, 0 },
@ -5824,8 +5826,8 @@ static int get_symbols (qse_awk_t* awk, qse_cint_t c, qse_awk_tok_t* tok)
{ QSE_T("&&"), 2, TOK_LAND, 0 },
{ QSE_T("&="), 2, TOK_BAND_ASSN, 0 },
{ QSE_T("&"), 1, TOK_BAND, 0 },
{ QSE_T("^^="), 3, TOK_BXOR_ASSN, QSE_AWK_EXTRAOPS },
{ QSE_T("^^"), 2, TOK_BXOR, QSE_AWK_EXTRAOPS },
{ QSE_T("^^="), 3, TOK_BXOR_ASSN, 0 },
{ QSE_T("^^"), 2, TOK_BXOR, 0 },
{ QSE_T("^="), 2, TOK_EXP_ASSN, 0 },
{ QSE_T("^"), 1, TOK_EXP, 0 },
{ QSE_T("++"), 2, TOK_PLUSPLUS, 0 },
@ -5834,19 +5836,20 @@ static int get_symbols (qse_awk_t* awk, qse_cint_t c, qse_awk_tok_t* tok)
{ QSE_T("--"), 2, TOK_MINUSMINUS, 0 },
{ QSE_T("-="), 2, TOK_MINUS_ASSN, 0 },
{ QSE_T("-"), 1, TOK_MINUS, 0 },
{ QSE_T("**="), 3, TOK_EXP_ASSN, QSE_AWK_EXTRAOPS },
{ QSE_T("**"), 2, TOK_EXP, QSE_AWK_EXTRAOPS },
{ QSE_T("**="), 3, TOK_EXP_ASSN, 0 },
{ QSE_T("**"), 2, TOK_EXP, 0 },
{ QSE_T("*="), 2, TOK_MUL_ASSN, 0 },
{ QSE_T("*"), 1, TOK_MUL, 0 },
{ QSE_T("/="), 2, TOK_DIV_ASSN, 0 },
{ QSE_T("/"), 1, TOK_DIV, 0 },
{ QSE_T("\\="), 2, TOK_IDIV_ASSN, QSE_AWK_EXTRAOPS },
{ QSE_T("\\"), 1, TOK_IDIV, QSE_AWK_EXTRAOPS },
{ QSE_T("%%="), 3, TOK_CONCAT_ASSN, QSE_AWK_EXPLICIT },
{ QSE_T("%%"), 2, TOK_CONCAT, QSE_AWK_EXPLICIT },
{ QSE_T("\\="), 2, TOK_IDIV_ASSN, 0 },
{ QSE_T("\\"), 1, TOK_IDIV, 0 },
{ QSE_T("%%="), 3, TOK_CONCAT_ASSN, 0 },
{ QSE_T("%%"), 2, TOK_CONCAT, 0 },
{ QSE_T("%="), 2, TOK_MOD_ASSN, 0 },
{ QSE_T("%"), 1, TOK_MOD, 0 },
{ QSE_T("~"), 1, TOK_TILDE, 0 },
{ QSE_T("~~"), 2, TOK_BNOT, 0 },
{ QSE_T("~"), 1, TOK_MA, 0 },
{ QSE_T("("), 1, TOK_LPAREN, 0 },
{ QSE_T(")"), 1, TOK_RPAREN, 0 },
{ QSE_T("{"), 1, TOK_LBRACE, 0 },
@ -5898,6 +5901,7 @@ static int get_token_into (qse_awk_t* awk, qse_awk_tok_t* tok)
{
qse_cint_t c;
int n;
int skip_semicolon_after_include = 0;
retry:
do
@ -5920,7 +5924,9 @@ retry:
if (n <= -1) return -1;
if (n >= 1)
{
awk->sio.last = awk->sio.inp->last;
/*awk->sio.last = awk->sio.inp->last;*/
/* mark that i'm retrying after end of an included file */
skip_semicolon_after_include = 1;
goto retry;
}
@ -5977,50 +5983,6 @@ retry:
QSE_STR_PTR(tok->name),
QSE_STR_LEN(tok->name));
SET_TOKEN_TYPE (awk, tok, type);
#if 0
if (type == TOK_IDENT)
{
qse_awk_sio_lxc_t lc;
while (c == QSE_T(':'));
{
lc = awk->sio.last;
GET_CHAR_TO (awk, c);
if (c == QSE_T(':'))
{
GET_CHAR_TO (awk, c);
if (c == QSE_T('_') || QSE_AWK_ISALPHA (awk, c))
{
do
{
ADD_TOKEN_CHAR (awk, tok, c);
GET_CHAR_TO (awk, c);
}
while (c == QSE_T('_') ||
QSE_AWK_ISALPHA (awk, c) ||
QSE_AWK_ISDIGIT (awk, c));
/* this set_token_type may get executed
* more than necessary if there are many
* segments. but never mind */
SET_TOKEN_TYPE (awk, tok, TOK_SEGIDENT);
}
else
{
/* TODO: return an error for the
* incomplete segmented identifier */
}
}
else
{
unget_char (awk, &awk->sio.last);
awk->sio.last = lc;
break;
}
}
}
#endif
}
else if (c == QSE_T('\"'))
{
@ -6044,11 +6006,26 @@ retry:
else
{
qse_char_t cc = (qse_char_t)c;
SETERR_ARG_LOC (
awk, QSE_AWK_ELXCHR, &cc, 1, &tok->loc);
SETERR_ARG_LOC (awk, QSE_AWK_ELXCHR, &cc, 1, &tok->loc);
}
return -1;
}
if (skip_semicolon_after_include && (tok->type == TOK_SEMICOLON || tok->type == TOK_NEWLINE))
{
/* this handles the optional semicolon after the
* included file named as in @include "file-name"; */
skip_semicolon_after_include = 0;
goto retry;
}
}
if (skip_semicolon_after_include && !(awk->opt.trait & QSE_AWK_NEWLINE))
{
/* semiclon has not been skipped yet and the
* newline option is not set. */
qse_awk_seterror (awk, QSE_AWK_ESCOLON, QSE_STR_CSTR(tok->name), &tok->loc);
return -1;
}
return 0;

View File

@ -161,6 +161,11 @@ static qse_awk_val_t* eval_binop_bxor (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right);
static qse_awk_val_t* eval_binop_band (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right);
static qse_awk_val_t* eval_binop_teq (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right);
static qse_awk_val_t* eval_binop_tne (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right);
static qse_awk_val_t* eval_binop_eq (
qse_awk_rtx_t* run, qse_awk_val_t* left, qse_awk_val_t* right);
static qse_awk_val_t* eval_binop_ne (
@ -309,12 +314,12 @@ static int set_global (
/* once a variable becomes a map,
* it cannot be changed to a scalar variable */
if (var != QSE_NULL)
if (var)
{
/* global variable */
SETERR_ARGX_LOC (
rtx,
QSE_AWK_EMAPTOSCALAR,
QSE_AWK_EMAPNA,
xstr_to_cstr(&var->id.name),
&var->loc
);
@ -324,7 +329,7 @@ static int set_global (
/* qse_awk_rtx_setgbl has been called */
qse_cstr_t ea;
ea.ptr = qse_awk_getgblname (rtx->awk, idx, &ea.len);
SETERR_ARGX (rtx, QSE_AWK_EMAPTOSCALAR, &ea);
SETERR_ARGX (rtx, QSE_AWK_EMAPNA, &ea);
}
return -1;
@ -656,7 +661,7 @@ int qse_awk_rtx_setofilename (
qse_awk_val_t* tmp;
int n;
if (rtx->awk->opt.trait & QSE_AWK_NEXTOFILE)
if (rtx->awk->opt.trait & QSE_AWK_EXTRAKWS)
{
if (len == 0) tmp = qse_awk_val_zls;
else
@ -2319,8 +2324,7 @@ static int run_return (qse_awk_rtx_t* run, qse_awk_nde_return_t* nde)
/* cannot return a map */
qse_awk_rtx_refupval (run, val);
qse_awk_rtx_refdownval (run, val);
SETERR_LOC (run, QSE_AWK_EMAPNA, &nde->loc);
SETERR_LOC (run, QSE_AWK_EMAPPH, &nde->loc);
return -1;
}
}
@ -2590,7 +2594,7 @@ static int run_delete_named (qse_awk_rtx_t* rtx, qse_awk_nde_var_t* var)
return 0;
}
static int run_delete_nonnamed (qse_awk_rtx_t* rtx, qse_awk_nde_var_t* var)
static int run_delete_unnamed (qse_awk_rtx_t* rtx, qse_awk_nde_var_t* var)
{
qse_awk_val_t* val;
@ -2693,7 +2697,7 @@ static int run_delete (qse_awk_rtx_t* rtx, qse_awk_nde_delete_t* nde)
case QSE_AWK_NDE_GBLIDX:
case QSE_AWK_NDE_LCLIDX:
case QSE_AWK_NDE_ARGIDX:
return run_delete_nonnamed (rtx, var);
return run_delete_unnamed (rtx, var);
default:
QSE_ASSERTX (
@ -3321,6 +3325,7 @@ static qse_awk_val_t* eval_assignment (qse_awk_rtx_t* run, qse_awk_nde_t* nde)
qse_awk_val_t* val2, * tmp;
static binop_func_t binop_func[] =
{
/* this table must match qse_awk_assop_type_t in run.h */
QSE_NULL, /* QSE_AWK_ASSOP_NONE */
eval_binop_plus,
eval_binop_minus,
@ -3455,13 +3460,12 @@ static qse_awk_val_t* do_assignment_scalar (
pair = qse_htb_search (
run->named, var->id.name.ptr, var->id.name.len);
if (pair != QSE_NULL &&
((qse_awk_val_t*)QSE_HTB_VPTR(pair))->type == QSE_AWK_VAL_MAP)
if (pair && ((qse_awk_val_t*)QSE_HTB_VPTR(pair))->type == QSE_AWK_VAL_MAP)
{
/* once a variable becomes a map,
* it cannot be changed to a scalar variable */
SETERR_ARGX_LOC (
run, QSE_AWK_EMAPTOSCALAR,
run, QSE_AWK_EMAPNA,
xstr_to_cstr(&var->id.name), &var->loc);
return QSE_NULL;
}
@ -3495,7 +3499,7 @@ static qse_awk_val_t* do_assignment_scalar (
/* once the variable becomes a map,
* it cannot be changed to a scalar variable */
SETERR_ARGX_LOC (
run, QSE_AWK_EMAPTOSCALAR,
run, QSE_AWK_EMAPNA,
xstr_to_cstr(&var->id.name), &var->loc);
return QSE_NULL;
}
@ -3514,7 +3518,7 @@ static qse_awk_val_t* do_assignment_scalar (
/* once the variable becomes a map,
* it cannot be changed to a scalar variable */
SETERR_ARGX_LOC (
run, QSE_AWK_EMAPTOSCALAR,
run, QSE_AWK_EMAPNA,
xstr_to_cstr(&var->id.name), &var->loc);
return QSE_NULL;
}
@ -3718,6 +3722,8 @@ static qse_awk_val_t* eval_binary (qse_awk_rtx_t* run, qse_awk_nde_t* nde)
eval_binop_bxor,
eval_binop_band,
eval_binop_teq,
eval_binop_tne,
eval_binop_eq,
eval_binop_ne,
eval_binop_gt,
@ -4338,28 +4344,67 @@ static int __cmp_val (
return func[left->type*4+right->type] (rtx, left, right);
}
static qse_awk_val_t* eval_binop_eq (
qse_awk_rtx_t* rtx, qse_awk_val_t* left, qse_awk_val_t* right)
static int teq_val (qse_awk_rtx_t* rtx, qse_awk_val_t* left, qse_awk_val_t* right)
{
int n;
if (left == right)
if (left == right) n = 1;
else if (left->type != right->type) n = 0;
else
{
/* array comparison is not allowed but this special check
allows comparsion of an array with itself. let's not
care about this loophole. */
return qse_awk_val_one;
switch (left->type)
{
case QSE_AWK_VAL_NIL:
n = 1;
break;
case QSE_AWK_VAL_INT:
n = ((qse_awk_val_int_t*)left)->val ==
((qse_awk_val_int_t*)right)->val;
break;
case QSE_AWK_VAL_FLT:
n = ((qse_awk_val_flt_t*)left)->val ==
((qse_awk_val_flt_t*)right)->val;
break;
case QSE_AWK_VAL_STR:
n = qse_strxncmp (
((qse_awk_val_str_t*)left)->val.ptr,
((qse_awk_val_str_t*)left)->val.len,
((qse_awk_val_str_t*)right)->val.ptr,
((qse_awk_val_str_t*)right)->val.len) == 0;
break;
default:
/* map-x and map-y are always different regardless of
* their contents. however, if they are pointing to the
* same map value, it won't reach here but will be
* handled by the first check in this function */
n = 0;
break;
}
}
/*
if (left->type != right->type &&
(left->type == QSE_AWK_VAL_MAP || right->type == QSE_AWK_VAL_MAP))
{
return qse_awk_val_zero;
}
*/
return n;
}
n = __cmp_val (rtx, left, right);
static qse_awk_val_t* eval_binop_teq (
qse_awk_rtx_t* rtx, qse_awk_val_t* left, qse_awk_val_t* right)
{
return teq_val (rtx, left, right)? qse_awk_val_one: qse_awk_val_zero;
}
static qse_awk_val_t* eval_binop_tne (
qse_awk_rtx_t* rtx, qse_awk_val_t* left, qse_awk_val_t* right)
{
return teq_val (rtx, left, right)? qse_awk_val_zero: qse_awk_val_one;
}
static qse_awk_val_t* eval_binop_eq (
qse_awk_rtx_t* rtx, qse_awk_val_t* left, qse_awk_val_t* right)
{
int n = __cmp_val (rtx, left, right);
if (n == CMP_ERROR) return QSE_NULL;
return (n == 0)? qse_awk_val_one: qse_awk_val_zero;
}
@ -4367,25 +4412,7 @@ static qse_awk_val_t* eval_binop_eq (
static qse_awk_val_t* eval_binop_ne (
qse_awk_rtx_t* rtx, qse_awk_val_t* left, qse_awk_val_t* right)
{
int n;
if (left == right)
{
/* array comparison is not allowed but this special check
allows comparsion of an array with itself. let's not
care about this loophole. */
return qse_awk_val_zero;
}
/*
if (left->type != right->type &&
(left->type == QSE_AWK_VAL_MAP || right->type == QSE_AWK_VAL_MAP))
{
return qse_awk_val_one;
}
*/
n = __cmp_val (rtx, left, right);
int n = __cmp_val (rtx, left, right);
if (n == CMP_ERROR) return QSE_NULL;
return (n != 0)? qse_awk_val_one: qse_awk_val_zero;
}

View File

@ -24,7 +24,12 @@
enum qse_awk_assop_type_t
{
/* if you change this, you have to change assop_str in tree.c.
* synchronize it with binop_func of eval_assignment in run.c */
* synchronize it wit:
* - binop_func in eval_assignment of run.c
* - assop in assing_to_opcode of parse.c
* - TOK_XXX_ASSN in tok_t in parse.c
* - assop_str in tree.c
*/
QSE_AWK_ASSOP_NONE,
QSE_AWK_ASSOP_PLUS, /* += */
QSE_AWK_ASSOP_MINUS, /* -= */
@ -37,7 +42,7 @@ enum qse_awk_assop_type_t
QSE_AWK_ASSOP_RS, /* >>= */
QSE_AWK_ASSOP_LS, /* <<= */
QSE_AWK_ASSOP_BAND, /* &= */
QSE_AWK_ASSOP_BXOR, /* ^= */
QSE_AWK_ASSOP_BXOR, /* ^^= */
QSE_AWK_ASSOP_BOR /* |= */
};
@ -53,6 +58,8 @@ enum qse_awk_binop_type_t
QSE_AWK_BINOP_BXOR,
QSE_AWK_BINOP_BAND,
QSE_AWK_BINOP_TEQ,
QSE_AWK_BINOP_TNE,
QSE_AWK_BINOP_EQ,
QSE_AWK_BINOP_NE,
QSE_AWK_BINOP_GT,

View File

@ -23,6 +23,7 @@
static const qse_char_t* assop_str[] =
{
/* this table must match qse_awk_assop_type_t in run.h */
QSE_T("="),
QSE_T("+="),
QSE_T("-="),
@ -30,11 +31,12 @@ static const qse_char_t* assop_str[] =
QSE_T("/="),
QSE_T("\\="),
QSE_T("%="),
QSE_T("**="),
QSE_T("**="), /* exponentation, also ^= */
QSE_T("%%="),
QSE_T(">>="),
QSE_T("<<="),
QSE_T("&="),
QSE_T("^="),
QSE_T("^^="),
QSE_T("|=")
};
@ -45,9 +47,11 @@ static const qse_char_t* binop_str[][2] =
{ QSE_T("in"), QSE_T("in") },
{ QSE_T("|"), QSE_T("|") },
{ QSE_T("^"), QSE_T("^") },
{ QSE_T("^^"), QSE_T("^^") },
{ QSE_T("&"), QSE_T("&") },
{ QSE_T("==="), QSE_T("===") },
{ QSE_T("!=="), QSE_T("!==") },
{ QSE_T("=="), QSE_T("==") },
{ QSE_T("!="), QSE_T("!=") },
{ QSE_T(">"), QSE_T(">") },
@ -64,9 +68,9 @@ static const qse_char_t* binop_str[][2] =
{ QSE_T("/"), QSE_T("/") },
{ QSE_T("\\"), QSE_T("\\") },
{ QSE_T("%"), QSE_T("%") },
{ QSE_T("**"), QSE_T("**") },
{ QSE_T("**"), QSE_T("**") }, /* exponentation, also ^ */
{ QSE_T(" "), QSE_T(".") },
{ QSE_T(" "), QSE_T("%%") }, /* take note of this entry */
{ QSE_T("~"), QSE_T("~") },
{ QSE_T("!~"), QSE_T("!~") }
};
@ -76,7 +80,7 @@ static const qse_char_t* unrop_str[] =
QSE_T("+"),
QSE_T("-"),
QSE_T("!"),
QSE_T("~")
QSE_T("~~")
};
static const qse_char_t* incop_str[] =

View File

@ -106,7 +106,7 @@ static void free_uctx_node (qse_awk_rtx_t* rtx, uctx_list_t* list, uctx_node_t*
list->map.tab[node->id] = QSE_NULL;
uci_free_context (node->ctx);
if (node->ctx) uci_free_context (node->ctx);
if (list->map.high == node->id + 1)
{
@ -118,6 +118,7 @@ static void free_uctx_node (qse_awk_rtx_t* rtx, uctx_list_t* list, uctx_node_t*
else
{
/* otherwise, chain the node to the free list */
node->ctx = QSE_NULL;
node->next = list->free;
list->free = node;
}
@ -135,7 +136,7 @@ static void free_uctx_node (qse_awk_rtx_t* rtx, uctx_list_t* list, uctx_node_t*
{
curnode = list->free;
list->free = list->free->next;
uci_free_context (curnode->ctx);
QSE_ASSERT (curnode->ctx == QSE_NULL);
QSE_MMGR_FREE (mmgr, curnode);
}

View File

@ -174,11 +174,11 @@ PROGS="
lang-045.awk!!!--newline=on -d-
lang-046.awk!lang-046.dat2!!--newline=on -d- -vdatadir=@abs_srcdir@ -vdatafile=lang-046.dat1
lang-047.awk!!!--newline=on --tolerant=on -d-
lang-048.awk!!!--newline=on --extraops=on -d-
lang-048.awk!!!--newline=on -d-
lang-049.awk!!!--newline=on -d-
columnate.awk!passwd.dat!!--newline=on -F:
levenshtein-utests.awk!!!--newline=on --include=on
levenshtein-utests.awk!!!--newline=on --extrakws=on
rcalc.awk!!!--newline=on -v target=89000
quicksort.awk!quicksort.dat!!
quicksort2.awk!quicksort2.dat!!-vQSEAWK=\"${QSEAWK}\" -vSCRIPT_PATH=\"${SCRIPT_DIR}\"

View File

@ -53,7 +53,6 @@ int main ()
/* don't allow BEGIN, END, pattern-action blocks */
opt &= ~QSE_AWK_PABLOCK;
/* enable ** */
opt |= QSE_AWK_EXTRAOPS;
qse_awk_setopt (awk, QSE_AWK_TRAIT, &opt);

View File

@ -139,7 +139,7 @@ static int awk_main (int argc, qse_char_t* argv[])
awk.setTrait (
awk.getTrait() |
QSE_AWK_MAPTOVAR |
QSE_AWK_RESET);
QSE_AWK_EXTRAKWS);
if (ret >= 0) ret = run_awk (awk);
if (ret <= -1)

View File

@ -356,8 +356,7 @@ static int awk_main_2 (MyAwk& awk, int argc, qse_char_t* argv[])
cmdline_t cmdline;
int n;
awk.setTrait (awk.getTrait() | QSE_AWK_INCLUDE |
QSE_AWK_MAPTOVAR | QSE_AWK_RWPIPE | QSE_AWK_EXTRAOPS);
awk.setTrait (awk.getTrait() | QSE_AWK_EXTRAKWS | QSE_AWK_MAPTOVAR | QSE_AWK_RWPIPE);
// ARGV[0]
if (awk.addArgument (QSE_T("awk08")) <= -1)

View File

@ -64,7 +64,7 @@ int main ()
}
qse_awk_getopt (awk, QSE_AWK_TRAIT, &opt);
opt |= QSE_AWK_NEXTOFILE;
opt |= QSE_AWK_EXTRAKWS;
qse_awk_setopt (awk, QSE_AWK_TRAIT, &opt);
psin.type = QSE_AWK_PARSESTD_STR;

View File

@ -59,8 +59,6 @@ int main ()
opt &= ~QSE_AWK_PABLOCK;
/* can assign a map to a variable */
opt |= QSE_AWK_MAPTOVAR;
/* enable ** */
opt |= QSE_AWK_EXTRAOPS;
qse_awk_setopt (awk, QSE_AWK_TRAIT, &opt);
psin.type = QSE_AWK_PARSESTD_STR;