From dbeb998018ce3a739500f9a29e9b62639de2c49f Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Mon, 27 Dec 2021 15:47:17 +0100 Subject: Added autocheck.l utility to check for wrong usage of c_auto*. --- autocheck.ll | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++++ build_autocheck.sh | 5 +++ examples/new_smap.c | 8 +++-- 3 files changed, 111 insertions(+), 3 deletions(-) create mode 100644 autocheck.ll create mode 100644 build_autocheck.sh diff --git a/autocheck.ll b/autocheck.ll new file mode 100644 index 00000000..9b090b1c --- /dev/null +++ b/autocheck.ll @@ -0,0 +1,101 @@ +/* Check for illegal return/break/continue usage inside a STC-lib c_auto* block (RAII). + * Copyright Tyge Løvset, (c) 2021. + */ +%{ +#include +enum { LOOP=1<<0, AUTO=1<<1 }; +enum { NORMAL, BRACES, BRACESDONE }; +static int braces_lev = 0, block_lev = 0; +static int state = NORMAL; +static unsigned int block[64] = {0}, block_type = 0; +const char* fname; +%} + +ID [_a-zA-Z][_a-zA-Z0-9]* +STR \"([^"\\]|\\.)*\" + +%option never-interactive noyymore noyywrap nounistd +%x cmt +%x prep + +%% +\/\/.* ; // line cmt +\/\* BEGIN(cmt); +\n ++yylineno; +\*\/ BEGIN(INITIAL); +. ; +^[ \t]*#.*\\\n { ++yylineno; BEGIN(prep); } +.*\\\n ++yylineno; +.*\n { ++yylineno; BEGIN(INITIAL); } +^[ \t]*#.* ; +{STR} ; +'\\?.' ; +c_foreach | +c_forrange | +for | +while | +switch { block_type |= LOOP; state = BRACES; } +do { block_type |= LOOP; state = BRACESDONE; } +if { state = BRACES; } +c_autovar | +c_autoscope | +c_autodefer | +c_auto { block_type = AUTO; state = BRACES; } +\( { if (state == BRACES) ++braces_lev; } +\) { if (state == BRACES && --braces_lev == 0) { + state = BRACESDONE; + } + } +;[ \t]*else ; +; { if (state == BRACESDONE) { + block_type = block[block_lev]; + state = NORMAL; + } + } +\{ { if (state != BRACES) { block[++block_lev] = block_type; state = NORMAL; } } +\} { if (state != BRACES) block_type = block[--block_lev]; } +return { if (block_type == AUTO) { + printf("%s:%d: error: 'return' used inside a c_auto* scope.\n" + " Use 'c_exitauto' to exit the current c_auto* scope.\n", fname, yylineno); + } else if (block_type & AUTO) { + printf("%s:%d: error: 'return' used in a loop inside a c_auto* scope.\n" + " Use 'break' to exit loops, then 'c_exitauto' to exit c_auto*.\n", fname, yylineno); + } + } +break { if (block_type == AUTO) + printf("%s:%d: error: 'break' used inside a c_auto* scope.\n" + " Use 'c_exitauto' to exit the current c_auto* scope.\n", fname, yylineno); + } +continue { if (block_type == AUTO) + printf("%s:%d: warning: 'continue' used inside a c_auto* scope.\n" + " It will only break out of the current c_auto* scope.\n" + " Use 'c_exitauto' instead to make it explicit.\n", fname, yylineno); + } +c_exitauto { if (block_type != AUTO) + printf("%s:%d: warning: 'c_exitauto' used outside a c_auto* scope.\n" + " Did you mean 'continue' instead?", fname, yylineno); + } +{ID} ; +\n ++yylineno; +. ; + +%% + +#include + +int main(int argc, char **argv) +{ + if (argc == 1 || strcmp(argv[1], "--help") == 0) { + printf("usage: %s [--help] {C-file | -}\n", argv[0]); + return 0; + } + if (strcmp(argv[1], "-") == 0) { + fname = ""; + yyin = stdin; + } else { + fname = argv[1]; + yyin = fopen(fname, "r"); + } + + yylex(); +} diff --git a/build_autocheck.sh b/build_autocheck.sh new file mode 100644 index 00000000..96ec7d4d --- /dev/null +++ b/build_autocheck.sh @@ -0,0 +1,5 @@ +if [ "$OS" = "Windows_NT" ]; then EXE=.exe; fi +flex autocheck.ll +gcc -O2 lex.yy.c -o autocheck$EXE +rm lex.yy.c +strip autocheck$EXE diff --git a/examples/new_smap.c b/examples/new_smap.c index 2cb35b99..e1a9b13a 100644 --- a/examples/new_smap.c +++ b/examples/new_smap.c @@ -43,9 +43,11 @@ int main() csmap_int_insert(&map, 123, 321); c_auto (csmap_pnt, pmap) { - csmap_pnt_insert(&pmap, (Point){42, 14}, 1); - csmap_pnt_insert(&pmap, (Point){32, 94}, 2); - csmap_pnt_insert(&pmap, (Point){62, 81}, 3); + c_apply(v, csmap_pnt_insert(&pmap, c_pair(v)), csmap_pnt_value, { + {{42, 14}, 1}, + {{32, 94}, 2}, + {{62, 81}, 3}, + }); c_foreach (i, csmap_pnt, pmap) printf(" (%d,%d: %d)", i.ref->first.x, i.ref->first.y, i.ref->second); puts(""); -- cgit v1.2.3