Common epilogue code in every Bison action - parsing

I need to execute exactly the same block of code at the end of every action of Bison grammar rules. Currently, to achieve that, I need to manually write ACTION_EPILOGUE before each closing curly brace. Number of actions is huge, and I may easily forget to add it somewhere.
...
%start start
%%
...
start: keyword options
;
keyword: KEYWORD {
handle_keyword($1);
ACTION_EPILOGUE;
};
options: /* empty */
| option {ACTION_EPILOGUE;}
| options ',' option {ACTION_EPILOGUE;}
;
option: edit_option {ACTION_EPILOGUE;}
| delete_option {ACTION_EPILOGUE;}
;
edit_option: EDIT {
process_edit($1);
ACTION_EPILOGUE;
};
// more rules and actions
...
Is there an option/method to instruct Bison to add the same block of code to the end of each action?

Related

How evaluate external command to a Nix value?

I want to parse a file to a Nix list value inside flake.nix.
I have a shell script which does that
perl -007 -nE 'say for m{[(]use-package \s* ([a-z-0-9]+) \s* (?!:nodep)}xsgm' init.el
How can I execute external command while evaluating flake.nix?
programs.emacs = {
enable = true;
extraConfig = builtins.readFile ./init.el;
extraPackages = elpa: (shellCommandToParseFile ./init.el); # Runs shell script
};
You can run ./init.el by the same way you perform any other impure step in Nix: With a derivation.
This might look something vaguely like:
programs.emacs = {
enable = true;
extraConfig = ../init.el;
extraPackages = elpa:
let
packageListNix =
pkgs.runCommand "init-packages.nix" { input = ../init.el; } ''
${pkgs.perl}/bin/perl -007 -nE '
BEGIN {
say "{elpa, ...}: with elpa; [";
say "use-package";
};
END { say "]" };
while (m{[(]use-package \s* ([a-z-0-9]+) \s* (;\S+)?}xsgm) {
next if $2 eq ";builtin";
say $1;
}' "$input" >"$out"
'';
in (import "${packageListNix}" { inherit elpa; });
};
...assuming that, given the contents of your ./init.el, the contents of your resulting el-pkgs.nix is actually valid nix source code.
That said, note that like any other derivation (that isn't either fixed-output or explicitly impure), this happens inside a sandbox with no network access. If the goal of init.el is to connect to a network resource, you should be committing its output to your repository. A major design goal of flakes is to remove impurities; they're not suitable for impure derivations.

How to stop parsing and reset yacc?

I am writing a job control shell. I use Yacc and Lex for parsing. The top rule in my grammar is pipeline_list, which is a list of pipelines separated by a comma. Thus, examples of pipelinelists are as follows:
cmd1 | cmd2; cmd3; cmd4 | cmd5 <newline>
cmd1 <newline>
<nothing> <newline>
I represent a pipeline with the pipeline rule (showed below). within that rule, I do the following:
1. call execute_pipeline() to execute the pipeline. execute_pipeline() returns -1 if anything went wrong in the execution of the pipeline.
2. Check the return value of execute_pipeline() and if it is -1, then STOP parsing the rest of the input, AND make sure YACC starts fresh when called again in the main function (shown below). The rationale for doing this is this:
Take, for example, the following pipelinelist: cd ..; ls -al. My intent here would be to move one directory up, and then list its content. However, if execution of the first pipeline (i.e., "cd ..") in the pipelinelist fails, then carrying on to execute the second pipeline (i.e. " ls -al") would list of the contents of the current directory (not the parent), which is wrong! For this reason, when parsing a pipelinelist of length n, if executing of some pipeline k > n fails, then I want to discard the rest of the pipelinelist (i.e., pipelines k+1..n), AND make sure the next invocation of yyparse() starts brand new (i.e. recieve new input from readline() -- see code below).
if tried the following, but it does not work:
pipeline:
simple_command_list redirection_list background pipeline_terminator // ignore these
{
if (execute_pipeline() == -1)
{
// do some stuff
// then call YYABORT, YYACCEPT, or YYERROR, but none of them works
}
}
int main()
{
while(1)
{
char *buffer = readline("> ");
if (buffer)
{
struct yy_buffer_state *bp;
bp = yy_scan_string(buffer);
yy_switch_to_buffer(bp);
yyparse()
yy_delete_buffer(bp);
free(buffer);
} // end if
} // end while
return 0;
} // end main()
You can use YYABORT; in an action to abort the current parse and immediately return from yyparse with a failure. You can use YYACCEPT; to immediately return success from yyparse.
Both of these macros can only be used directly in an action in the grammar -- they can't be used in some other function called by the action.

how to define and use a compile time macro?

I'm trying to understand more about settings macros for compilation.
The Erlang compile documentation shows that a macro can be defined:
{d,Macro} {d,Macro,Value}
Defines a macro Macro to have the value Value.
Macro is of type atom, and Value can be any term.
The default Value is true.
I'm trying to set a macro using a directive:
-module(my_mod).
-compile([debug_info, {d, debug_level, 1}]).
...
How would I use this macro in my code? For example I have tried this:
my_func() ->
if
debug_level == 1 -> io:format("Warning ...");
true -> io:format("Error ...")
end.
But 'Error ...' is always output.
Where am I going wrong?
You can set a macro in your code using -define:
-define(debug_level, 1).
If you want to be able to override it from the compilation command line, you can wrap it with -ifndef:
-ifndef(debug_level).
-define(debug_level, 1).
-endif.
This way, if you compile with
erlc -Ddebug_level=2 file.erl
for example, then the macro will have the value 2 instead of the default value 1.
To access the value of a macro, you prepend it with a ?:
my_func() ->
if
?debug_level == 1 -> io:format("Warning ...");
true -> io:format("Error ...")
end.
Note that since ?debug_level is a constant, you'll get compiler warnings from the if expression about clauses that can never match.

Line break support in parser (TCL)

So, I have a parser, written in TCL. There are many commands in the parsing file. Now, I need to add support for line breaks.
For ex.
my_command \
arg1 \
arg2 \
arg3
I have something like this.
while { ! [eof $currentFileDescriptor] } {
set line [gets $currentFileDescriptor]
set lst [lindex [regexp -all -inline {^(\s*(\S*)\s*)*(\{(.*)\})?(\s*(\S*)\s*)*$} $line] 0]
set tok [string toupper [lindex $lst 0]]
switch -glob $tok {
"\#*" { }
"MY_COMMAND_1" { parseMyCommand1 $handler $lst }
.....#other commands }
}
incr lnum
}
I am looking for an optimal and effective solution.
It looks like you have defined a domain specific language (DSL) with the parsing implemented in Tcl. You may as well use the Tcl parsing itself to deal with things like line continuation and quote handling. The method to do this is to create a safe interpreter and in the safe interpreter only provide the commands required for your DSL. You then interpret your config file in the safe child interpreter. The wiki page has some examples.
The advantage of this method is that the parsing is handled by the normal Tcl parser. However you can be in complete control of what commands are exposed in the safe interpreter. You can also control the amount of resources it can use (stack and memory) and limit it's visibility of the filesystem or network.
If you don't want to get into this then you just need to implement recognition of backslashed newlines and buffer such lines until you have a complete line. Something like the following (untested):
set linenum 0
set buffer ""
while {[gets $input line] != -1} {
incr linenum
if {[regexp {\\$} $line]} {
append buffer [string range $line 0 end-1]
continue
} else {
append buffer $line
}
ParseCompleteLine $linenum $buffer
set buffer ""
}

Is there any way for jscs to ignore rules per file, block or line?

I'm looking for a way for jscs (JavaScript Code Style) do the same behavior as jshint to ignore certain rules per file with a comment at the top, or per line, with a start and end comment.
jshint example to ignore a specific rule in the file :
/* jshint undef: false */
jshint example to ignore a specific rule in a block:
// Code here will be linted with JSHint.
/* jshint ignore:start */
// Code here will be linted with ignored by JSHint.
/* jshint ignore:end */
This is available since jscs 1.6.0
For a file scope:
Put this on top of the file to ignore all rules
// jscs:disable
Put this on top of the file to ignore a specific rule:
// jscs:disable specificRule
Also for ignoring the whole file you can add it to .jscsrc, adding an entry to excludeFiles.
For block scope:
To ignore all rules
// Code here will be linted with JSCS.
// jscs:disable
// Code here will be ignored by JSCS.
// jscs:enable
To ignore a specific rule:
// Code here will be linted with JSCS.
// jscs:disable specificRule
// Code here will be ignored by JSCS.
// jscs:enable specificRule
to disable a particular rule for just the one line
// jscs:ignore maximumLineLength
To ignore the whole file just add the following line at the top of the file.
// jscs:disable

Resources