Commit 333a6266 authored by jan.koester's avatar jan.koester
Browse files

bugfix flex

parent 34f59163
Loading
Loading
Loading
Loading
+3 −1
Changes for lib/flex/flex.cpp: 3 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -1988,6 +1988,7 @@ std::string CodeGenerator::generateSource() {

    if (!o.noUnistd)
        out << "#ifndef YY_NO_UNISTD_H\n#include <unistd.h>\n#endif\n";
    if (!o.extraType.empty()) out << "#define YY_EXTRA_TYPE " << o.extraType << "\n";
    out << "#ifndef YY_EXTRA_TYPE\n#define YY_EXTRA_TYPE void *\n#endif\n\n";

    // ---- scanner state ----
@@ -2021,7 +2022,8 @@ std::string CodeGenerator::generateSource() {
    // yywrap: without noyywrap the program brings its own, or -lfl would
    if (o.yywrap) {
        out << "int yywrap( FX_PROTO );\n";
        if (!hasWord(s.userCode, o.prefix == "yy" ? "yywrap" : o.prefix + "wrap") && !hasWord(s.userCode, "yywrap"))
        const std::string wrap = o.prefix + "wrap", code = s.prologue + s.userCode;
        if (!hasWord(code, wrap) && !hasWord(code, "yywrap"))
            out << "#if defined(__GNUC__) || defined(__clang__)\n__attribute__((weak))\n#endif\n"
                   "int yywrap( FX_PROTO ) { FX_UNUSED; return 1; }\n";
    }

lib/flex/test/run.sh

0 → 100644
+348 −0
Changes for lib/flex/test/run.sh: 348 added lines, 0 removed lines.
Original line number Diff line number Diff line
#!/bin/bash
# flex test suite: usage: run.sh FLEX CC  (FLEX: the fresh binary's flex applet)
# Each case is a scanner, its input, and the output it has to print.
FLEX=${1:-flex}; CC=${2:-cc}
T=$(mktemp -d); trap 'rm -rf "$T"' EXIT
pass=0; fail=0
# what -lfl would bring
echo 'extern int yylex(); __attribute__((weak)) int main(void){ yylex(); return 0; }' > "$T/m0.c"

# check NAME LFILE INPUT EXPECTED
check() {
    local name=$1 l=$2 input=$3 want=$4 got
    if ! (cd "$T" && $FLEX -o s.c "$l" 2>err.txt && $CC -std=gnu99 -Wall -Werror=implicit-function-declaration -Wno-unused -o s s.c m0.c 2>>err.txt); then
        echo "FAIL $name (build)"; head -8 "$T/err.txt"; fail=$((fail+1)); return
    fi
    got=$(printf "$input" | "$T/s" 2>&1)
    if [ "$got" = "$want" ]; then pass=$((pass+1)); else
        echo "FAIL $name"; echo "  want: $want"; echo "  got:  $got"; fail=$((fail+1))
    fi
}

cat > "$T/basic.l" <<'E'
%option noyywrap
%%
[0-9]+    printf("N(%s)", yytext);
if|then   { printf("K(%s)", yytext); }
[a-z]+    printf("I(%s/%d)", yytext, yyleng);
\n        printf("|%d", yylineno);
E
check longest+priority basic.l 'if iff 12\nx\n' 'K(if) I(iff/3) N(12)|2I(x/1)|3'

cat > "$T/alt.l" <<'E'
%option noyywrap
%%
a |
b |
c    printf("X");
.|\n ;
E
check bar-action alt.l 'abcd' 'XXX'

cat > "$T/bol.l" <<'E'
%option noyywrap
%%
^a   printf("B");
a$   printf("E");
a    printf("M");
\n   printf("|");
.    ;
E
check bol+eol bol.l 'aa\nxa\naxa' 'BE|E|BM'

cat > "$T/trail.l" <<'E'
%option noyywrap
%%
foo/bar   printf("[%s]", yytext);
a*/a*b    printf("<%s>", yytext);
.|\n      printf("%s", yytext);
E
check trailing trail.l 'foobar foo aab' '[foo]bar foo <aa>b'

cat > "$T/more.l" <<'E'
%option noyywrap
%%
mega-    yymore();
kludge   printf("[%s]", yytext);
.|\n     ;
E
check yymore more.l 'mega-kludge' '[mega-kludge]'

cat > "$T/rej.l" <<'E'
%option noyywrap
%{
int n;
%}
%%
frob   n++; REJECT;
[^ \t\n]+ n++;
.|\n   ;
%%
int main(void){ yylex(); printf("%d", n); return 0; }
E
check reject rej.l 'frob x' '3'

cat > "$T/less.l" <<'E'
%option noyywrap
%%
foobar   { printf("[%s]", yytext); yyless(3); printf("[%s]", yytext); }
bar      printf("B");
\n       ;
E
check yyless less.l 'foobar\n' '[foobar][foo]B'

cat > "$T/putin.l" <<'E'
%option noyywrap
%%
"("   { int c; while((c=input())!=')' && c) putchar(c); }
x     { unput('z'); unput('y'); }
y     printf("Y");
z     printf("Z");
.|\n  ;
E
check input+unput putin.l '(ab)x' 'abYZ'

cat > "$T/array.l" <<'E'
%array
%option noyywrap
%%
[a-z]+   printf("[%s]", yytext);
.|\n     ;
%%
extern char yytext[];
E
check array array.l 'ab cd' '[ab][cd]'

cat > "$T/cond.l" <<'E'
%option noyywrap stack
%x C
%s I
%%
"/*"     { yy_push_state(C); }
<C>"*/"  { yy_pop_state(); }
<C>.|\n  ;
<I,INITIAL>a  printf("A");
<*>b     printf("B");
.|\n     ;
<<EOF>>  { printf("E%d", YY_START); yyterminate(); }
<C><<EOF>> { printf("U"); yyterminate(); }
E
check conditions cond.l 'a/*ab*/b' 'ABBE0'
check eof-in-condition cond.l 'a/*x' 'AU'

cat > "$T/block.l" <<'E'
%option noyywrap
%x Q
hex  [0-9a-f]
%%
\"     BEGIN(Q);
<Q>{
    /* comment */
  \"       BEGIN(INITIAL);
  {hex}+   printf("H%s", yytext);
  <<EOF>>  { printf("!"); return 0; }
  .|\n     ;
} /* <Q> */
<Q>x   printf("never");
.|\n   ;
E
check condition-block block.l 'x"ag"x' 'Ha'

cat > "$T/case.l" <<'E'
%option noyywrap case-insensitive
%%
select   printf("S");
[a-c]+   printf("C");
.|\n     ;
E
check case-insensitive case.l 'SeLeCt ABC' 'SC'

cat > "$T/flags.l" <<'E'
%option noyywrap
%%
(?i:abc)def        printf("1");
(?s:a.b)           printf("2");
(?x: x  y  /* c */ z )  printf("3");
[a-z]{-}[aeiou]+q  printf("4");
[[:^digit:]]{+}[0]q printf("5");
(?# nothing )w     printf("6");
.|\n               ;
E
check group-flags flags.l 'ABcdef a\nb xyz bcq 0q w' '12345 6' 2>/dev/null

cat > "$T/rep.l" <<'E'
%option noyywrap
d  [0-9]
%%
{d}{2,3}x   printf("A");
{d}{4}y     printf("B");
(ab)+       printf("C%d", yyleng);
"lit*"      printf("D");
\x41\101    printf("E");
.|\n        ;
E
check repeat rep.l '12x 1234y ababab lit* AA' 'AB C6 D E'

cat > "$T/echo.l" <<'E'
%option noyywrap
%%
a   ;
E
check default-echo echo.l 'xay\n' 'xy'

cat > "$T/jam.l" <<'E'
%option noyywrap nodefault
%%
a   ;
E
check nodefault jam.l 'b' 'flex scanner jammed'

cat > "$T/nul.l" <<'E'
%option noyywrap 8bit
%%
\0     printf("N");
[\x80-\xff]+   printf("H%d", yyleng);
.|\n   ;
E
check binary nul.l 'a\0b\377\200' 'NH2'

cat > "$T/big.l" <<'E'
%option noyywrap
%%
a+     printf("%d\n", yyleng);
\n     printf("L%d\n", yylineno);
.      ;
E
input=$(head -c 100000 /dev/zero | tr '\0' a)
check long-token big.l "$input\n" "100000
L2"

cat > "$T/scan.l" <<'E'
%option noyywrap
%%
[a-z]+  printf("[%s]", yytext);
.|\n    ;
%%
int main(void){
    char b[8] = "ab cd\0\0";
    YY_BUFFER_STATE h = yy_scan_string("xy zw");
    yylex(); yy_delete_buffer(h);
    h = yy_scan_bytes("qr st", 2);
    yylex(); yy_delete_buffer(h);
    h = yy_scan_buffer(b, 7);
    yylex(); yy_delete_buffer(h);
    printf(" %d", b[0]=='a' && b[3]=='c');
    yylex_destroy();
    return 0;
}
E
check scan-api scan.l '' '[xy][zw][qr][ab][cd] 1'

cat > "$T/stack.l" <<'E'
%option noyywrap
%%
"<"     { yypush_buffer_state(yy_scan_string("in")); }
<<EOF>> { yypop_buffer_state(); if(!YY_CURRENT_BUFFER) yyterminate(); }
[a-z]+  printf("[%s]", yytext);
.|\n    ;
E
check buffer-stack stack.l 'a<b' '[a][in][b]'

cat > "$T/wrap.l" <<'E'
%{
static int files = 1;
int yywrap(void){ if(files--){ yy_scan_string("more"); return 0; } return 1; }
%}
%%
[a-z]+  printf("[%s]", yytext);
.|\n    ;
E
check yywrap wrap.l 'one' '[one][more]'

cat > "$T/hooks.l" <<'E'
%option noyywrap
%{
static int col;
#define YY_USER_ACTION col += yyleng;
#define YY_USER_INIT printf("I");
#define YY_INPUT(buf,result,max) { static const char *s="abc"; result = *s ? (buf[0]=*s++, 1) : 0; }
%}
%%
[a-z]  printf("%d", col);
E
check hooks hooks.l '' 'I123'

cat > "$T/re.l" <<'E'
%option reentrant noyywrap prefix="core_yy" extra-type="int *"
%%
[a-z]+  { (*yyextra)++; printf("[%s:%d]", yytext, *yyextra); }
x+y     { BEGIN(INITIAL); yyless(1); }
.|\n    ;
%%
int main(void){
    yyscan_t a, b; int na = 0, nb = 10; YY_BUFFER_STATE ha, hb;
    core_yylex_init_extra(&na, &a);
    core_yylex_init(&b);
    core_yyset_extra(&nb, b);
    ha = core_yy_scan_string("aa bb", a);
    hb = core_yy_scan_string("cc", b);
    core_yylex(a); core_yylex(b);
    core_yy_delete_buffer(ha, a); core_yy_delete_buffer(hb, b);
    printf(" %s", core_yyget_extra(a) == &na ? "ok" : "bad");
    core_yylex_destroy(a); core_yylex_destroy(b);
    return 0;
}
E
check reentrant+prefix re.l '' '[aa:1][bb:2][cc:11] ok'

cat > "$T/bb.l" <<'E'
%option reentrant bison-bridge bison-locations noyywrap
%{
typedef int YYSTYPE;
typedef struct { int first; } YYLTYPE;
%}
%%
[0-9]+   { *yylval = atoi(yytext); yylloc->first = yytext - (char *) yyextra; return 1; }
.|\n     ;
%%
int main(void){
    yyscan_t s; YYSTYPE v; YYLTYPE l; char buf[] = "  42\0";
    yylex_init(&s);
    yyset_extra(buf, s);
    yy_scan_buffer(buf, sizeof(buf), s);
    while(yylex(&v, &l, s)) printf("%d@%d", v, l.first);
    yylex_destroy(s);
    return 0;
}
E
check bison-bridge+text-in-buffer bb.l '' '42@2'

cat > "$T/fatal.l" <<'E'
%option noyywrap noyyalloc noyyrealloc noyyfree
%{
#undef fprintf
#define fprintf(file, fmt, msg) printf("fatal:%s", msg)
%}
%%
a   ;
%%
void *yyalloc(yy_size_t n){ static int once; if(!once++) printf("A"); return malloc(n); }
void *yyrealloc(void *p, yy_size_t n){ return realloc(p, n); }
void yyfree(void *p){ free(p); }
int main(void){ yylex(); yy_fatal_error("x"); }
E
check own-alloc+fprintf-hook fatal.l '' 'Afatal:x'

cat > "$T/hdr.l" <<'E'
%option noyywrap reentrant header-file="h.h" prefix="p"
%%
.|\n ;
E
if (cd "$T" && $FLEX -o h.c hdr.l && printf '#include "h.h"\nint main(void){ yyscan_t s; plex_init(&s); plex_destroy(s); return 0; }\n' > m.c && $CC -c m.c 2>err.txt); then pass=$((pass+1)); else echo "FAIL header-file"; head -5 "$T/err.txt"; fail=$((fail+1)); fi

(cd "$T" && $FLEX -t basic.l | grep -q yylex) && pass=$((pass+1)) || { echo "FAIL -t"; fail=$((fail+1)); }
(cd "$T" && $FLEX basic.l && [ -s lex.yy.c ] && $FLEX -Pfoo basic.l && [ -s lex.foo.c ]) && pass=$((pass+1)) || { echo "FAIL default output"; fail=$((fail+1)); }
(cd "$T" && echo '%option c++' > cc.l && echo '%%' >> cc.l && ! $FLEX -o /dev/null cc.l 2>/dev/null) && pass=$((pass+1)) || { echo "FAIL c++ must be an error"; fail=$((fail+1)); }

echo "$pass passed, $fail failed"
[ "$fail" = 0 ]