Skip to content

Instantly share code, notes, and snippets.

@jarble
Created January 13, 2019 09:28
Show Gist options
  • Save jarble/333374ae6677927be5d05962c4350794 to your computer and use it in GitHub Desktop.
Save jarble/333374ae6677927be5d05962c4350794 to your computer and use it in GitHub Desktop.
A Prolog-to-Python translator using list comprehensions
/* lexical grammar */
%lex
%%
\s+ /* skip whitespace */
[0-9]+("."[0-9]+)?\b return 'NUMBER'
\"([^\\\"]|\\.)*\" return 'STRING_LITERAL'
"forall" return 'forall'
"copy_term" return 'copy_term'
"if" return "if"
"is" return "is"
"," return ','
";" return ';'
"--->" return '--->'
"==>" return '==>'
"<=>" return '<=>'
"@" return '@'
"-->" return '-->'
"->" return '->'
":-" return ':-'
"." return '.'
":" return ':'
">=" return '>='
">" return '>'
"=<" return '=<'
"<" return '<'
"==" return '=='
"=" return '='
"*=" return '*='
"*" return '*'
"\\=" return '\\='
"/" return '/'
"-=" return '-='
"--" return '--'
"-" return '-'
"++" return '++'
"+=" return '+='
"+" return '+'
"^" return '^'
"{" return '{'
"}" return '}'
"|" return '|'
"[" return '['
"]" return ']'
"(" return '('
")" return ')'
[a-zA-Z_][a-zA-Z0-9_]* return 'IDENTIFIER'
<<EOF>> return 'EOF'
. return 'INVALID'
/lex
/* operator associations and precedence */
%left '->'
%left ';'
%left ','
%left '<' '=<' '>' '>=' '=' '==' '\\=' 'is'
%left '+' '-'
%left '*' '/'
%left UMINUS
%start expressions
%% /* language grammar */
expressions: top_level_statements EOF {return $1};
top_level_statements: top_level_statement "." top_level_statements {$$ = $1+"\n"+$3;} | top_level_statement "." {$$ =
$1;};
top_level_statement
: IDENTIFIER "(" exprs ")" ":-" predicate_ {$$ = "def "+$1+"():\n return [[" + $3.join()+"] for "+$6+"]"}
| IDENTIFIER ":-" e {$$ = ["def " + $1 + "():",$3]};
predicate_: logic_and_ "," "(" e ")" {$$ = $1 +" if "+$3} | logic_and_;
logic_and_: function_call | logic_and_ "," function_call {$$ = $1 + " for " + $3};
e
:
e '->' e
{$$ = ["(not("+$1+") or ("+$3+"))"]}
|e ';' e
{$$ = $1+ " or " +$3;}
|e ',' e
{$$ = $1+" and "+$3;}
|e '=' e
{$$ = $1+" == "+$3;}
|e 'is' e
{$$ = $1+"=="+$3;}
|e '\\=' e
{$$ = $1+"!="+$3;}
|e '==' e
{$$ = $1+"=="+$3;}
|e '=<' e
{$$ = $1+"<="+$3;}
|e '<' e
{$$ = $1+$2+$3;}
| e '>=' e
{$$ = $1+$2+$3;}
|e '>' e
{$$ = $1+$2+$3;}
| e '+' e
{$$ = $1+$2+$3;}
| e '-' e
{$$ = $1+$2+$3;}
| e '*' e
{$$ = $1+$2+$3;}
| e '/' e
{$$ = $1+$2+$3;}
| '-' e %prec UMINUS
{$$ = ["-",$2];}
| not_expr
;
not_expr: "\+" parentheses_expr {$$ = "(not "+$2+")";} | parentheses_expr {$$ = $1;};
parameter: IDENTIFIER {$$ = $1;};
parameters: parameter "," parameters {$$ = $1+","+$3;} | parameter {$$ =
$1;} | {$$ = ""};
function_call:
IDENTIFIER "(" ")" {$$ = [$1+"()"];} | IDENTIFIER "(" exprs ")" {
if($1 === "member"){
$$ = $3.join(" in ");
}
else{
$$ = ["["+$3.join(",")+"] in "+$1+"()"];
}
};
forall_statement: "forall" "(" e "," e ")" {$$ = ["forall",$3,$5];};
parentheses_expr:
forall_statement
| function_call
| '(' e ')' {$$ = "("+$2+")";}
| "[" "]" {$$ = "[]";}
| "[" exprs "]" {$$ = "["+$2.join(",")+"]";}
| "[" parentheses_expr "|" exprs "]" {$$ = "[" + $2 + "] + "+$4.join(",");}
| NUMBER
{$$ = yytext;}
| IDENTIFIER
{$$ = yytext;}
| STRING_LITERAL
{$$ = yytext;};
exprs: exprs "," parentheses_expr {$$ = $1.concat([$3]);} | parentheses_expr {$$ = [$1];};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment