* Basic grammar and parser for the Fix language. We use libsglr and
friends to do the parsing. The parse table is embedded in the Fix executable using bin2c, which converts an arbitrary file into a C character array.
This commit is contained in:
parent
4d728f6a36
commit
b95a3dc45b
6 changed files with 298 additions and 7 deletions
|
@ -1,8 +1,25 @@
|
|||
bin_PROGRAMS = fix-ng
|
||||
|
||||
fix_ng_SOURCES = fix.cc
|
||||
fix_ng_SOURCES = fix.cc parser.cc
|
||||
fix_ng_LDADD = ../libmain/libmain.a ../libnix/libnix.a ../boost/format/libformat.a \
|
||||
-L../../externals/inst/lib -ldb_cxx -lATerm
|
||||
-L../../externals/inst/lib -ldb_cxx -lsglr -lATB -lconversion -lasfix2 -lmept -lATerm
|
||||
|
||||
AM_CXXFLAGS = \
|
||||
-I.. -I../../externals/inst/include -I../libnix -I../libmain
|
||||
|
||||
|
||||
# Parse table generation.
|
||||
|
||||
parser.o: parse-table.h
|
||||
|
||||
parse-table.h: fix.tbl bin2c
|
||||
./bin2c fixParseTable < $< > $@ || (rm $@ && exit 1)
|
||||
|
||||
noinst_PROGRAMS = bin2c
|
||||
|
||||
bin2c_SOURCES = bin2c.c
|
||||
|
||||
%.tbl: %.sdf
|
||||
../../externals/inst/bin/sdf2table -i $< -o $@
|
||||
|
||||
CLEANFILES = parse-table.h fix.tbl
|
||||
|
|
23
src/fix-ng/bin2c.c
Normal file
23
src/fix-ng/bin2c.c
Normal file
|
@ -0,0 +1,23 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
void print(const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
if (vprintf(format, ap) < 0) abort();
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
int main(int argc, char * * argv)
|
||||
{
|
||||
int c;
|
||||
if (argc != 2) abort();
|
||||
print("static unsigned char %s[] = {", argv[1]);
|
||||
while ((c = getchar()) != EOF) {
|
||||
print("0x%02x, ", (unsigned char) c);
|
||||
}
|
||||
print("};\n");
|
||||
return 0;
|
||||
}
|
|
@ -1,13 +1,12 @@
|
|||
#include <map>
|
||||
#include <iostream>
|
||||
|
||||
#include "parser.hh"
|
||||
#include "globals.hh"
|
||||
#include "normalise.hh"
|
||||
#include "shared.hh"
|
||||
|
||||
|
||||
typedef ATerm Expr;
|
||||
|
||||
typedef map<ATerm, ATerm> NormalForms;
|
||||
typedef map<Path, PathSet> PkgPaths;
|
||||
typedef map<Path, Hash> PkgHashes;
|
||||
|
@ -406,9 +405,7 @@ static Expr evalFile(EvalState & state, const Path & relPath)
|
|||
{
|
||||
Path path = searchPath(state.searchDirs, relPath);
|
||||
Nest nest(lvlTalkative, format("evaluating file `%1%'") % path);
|
||||
Expr e = ATreadFromNamedFile(path.c_str());
|
||||
if (!e)
|
||||
throw Error(format("unable to read a term from `%1%'") % path);
|
||||
Expr e = parseExprFromFile(path);
|
||||
return evalExpr(state, e);
|
||||
}
|
||||
|
||||
|
|
163
src/fix-ng/fix.sdf
Normal file
163
src/fix-ng/fix.sdf
Normal file
|
@ -0,0 +1,163 @@
|
|||
definition
|
||||
|
||||
module Main
|
||||
imports Fix
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%% Top level syntax.
|
||||
|
||||
module Fix
|
||||
imports Fix-Exprs Fix-Layout
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%% Expressions.
|
||||
|
||||
module Fix-Exprs
|
||||
imports Fix-Lexicals URI
|
||||
exports
|
||||
sorts Expr Bind
|
||||
context-free syntax
|
||||
|
||||
Id
|
||||
-> Expr {cons("Var")}
|
||||
|
||||
Int
|
||||
-> Expr {cons("Int")}
|
||||
|
||||
Str
|
||||
-> Expr {cons("Str")}
|
||||
|
||||
Uri
|
||||
-> Expr {cons("Uri")}
|
||||
|
||||
Path
|
||||
-> Expr {cons("Path")}
|
||||
|
||||
"(" Expr ")"
|
||||
-> Expr {bracket}
|
||||
|
||||
Expr Expr
|
||||
-> Expr {cons("Call"), left}
|
||||
|
||||
"{" {Id ","}* "}" ":" Expr
|
||||
-> Expr {cons("Function"), right}
|
||||
|
||||
"{" {Bind ","}+ "}"
|
||||
-> Expr {cons("Attrs")}
|
||||
|
||||
Id "=" Expr
|
||||
-> Bind {cons("Bind")}
|
||||
|
||||
"[" {Expr ","}* "]"
|
||||
-> Expr {cons("List")}
|
||||
|
||||
context-free priorities
|
||||
|
||||
Expr Expr -> Expr
|
||||
> "{" {Id ","}* "}" ":" Expr -> Expr
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%% Lexical syntax.
|
||||
|
||||
module Fix-Lexicals
|
||||
exports
|
||||
sorts Id Path
|
||||
lexical syntax
|
||||
[a-zA-Z\_][a-zA-Z0-9\_\']* -> Id
|
||||
[0-9]+ -> Int
|
||||
"\"" ~[\n\"]* "\"" -> Str
|
||||
PathComp ("/" PathComp)+ -> Path
|
||||
[a-zA-Z0-9\.\_\-]+ -> PathComp
|
||||
lexical restrictions
|
||||
Id -/- [a-zA-Z0-9\_\']
|
||||
Int -/- [0-9]
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%% URIs (RFC 2396, appendix A).
|
||||
|
||||
module URI
|
||||
exports
|
||||
sorts Uri
|
||||
lexical syntax
|
||||
Uscheme ":" (Uhierpath | Uopaquepath) -> Uri
|
||||
|
||||
(Unetpath | Uabspath) ("?" Uquery)? -> Uhierpath
|
||||
Uuricnoslash Uuric* -> Uopaquepath
|
||||
|
||||
Uunreserved | Uescaped | [\;\?\:\@\&\=\+\$\,] -> Uuricnoslash
|
||||
|
||||
"//" Uauthority Uabspath? -> Unetpath
|
||||
"/" Upathsegments -> Uabspath
|
||||
Urelsegment Uabspath? -> Urelpath
|
||||
|
||||
(Uunreserved | Uescaped | [\;\@\&\=\+\$\,])+ -> Urelsegment
|
||||
|
||||
Ualpha (Ualpha | Udigit | [\+\-\.])* -> Uscheme
|
||||
|
||||
Userver | Uregname -> Uauthority
|
||||
|
||||
(Uunreserved | Uescaped | [\$\,\;\:\@\&\=\+])+ -> Uregname
|
||||
|
||||
((Uuserinfo "@") Uhostport) -> Userver
|
||||
(Uunreserved | Uescaped | [\;\:\&\=\+\$\,])* -> Uuserinfo
|
||||
|
||||
Uhost (":" Uport)? -> Uhostport
|
||||
Uhostname | UIPv4address -> Uhost
|
||||
(Udomainlabel ".")+ Utoplabel "."? -> Uhostname
|
||||
Ualphanum | Ualphanum (Ualphanum | "-")* Ualphanum -> Udomainlabel
|
||||
Ualpha | Ualpha (Ualphanum | "-")* Ualphanum -> Utoplabel
|
||||
Udigit+ "." Udigit+ "." Udigit+ "." Udigit+ -> UIPv4address
|
||||
Udigit* -> Uport
|
||||
|
||||
Uabspath | Uopaquepart -> Upath
|
||||
Usegment ("/" Usegment)* -> Upathsegments
|
||||
Upchar* (";" Uparam)* -> Usegment
|
||||
Upchar* -> Uparam
|
||||
Uunreserved | Uescaped | [\:\@\&\=\+\$\,] -> Upchar
|
||||
|
||||
Uuric* -> Uquery
|
||||
|
||||
Uuric* -> Ufragment
|
||||
|
||||
Ureserved | Uunreserved | Uescaped -> Uuric
|
||||
[\;\/\?\:\@\&\=\+\$\,] -> Ureserved
|
||||
Ualphanum | Umark -> Uunreserved
|
||||
[\-\_\.\!\~\*\'\(\)] -> Umark
|
||||
|
||||
"%" Uhex Uhex -> Uescaped
|
||||
Udigit | [A-Fa-f] -> Uhex
|
||||
|
||||
Ualpha | Udigit -> Ualphanum
|
||||
Ulowalpha | Uupalpha -> Ualpha
|
||||
|
||||
[a-z] -> Ulowalpha
|
||||
[A-Z] -> Uupalpha
|
||||
[0-9] -> Udigit
|
||||
|
||||
lexical restrictions
|
||||
Uri -/- [a-zA-Z0-9\-\_\.\!\~\*\'\(\)]
|
||||
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%% Layout.
|
||||
|
||||
module Fix-Layout
|
||||
exports
|
||||
lexical syntax
|
||||
[\ \t\n] -> LAYOUT
|
||||
HashComment -> LAYOUT
|
||||
Comment -> LAYOUT
|
||||
"#" ~[\n]* [\n] -> HashComment
|
||||
"//" ~[\n]* [\n] -> HashComment
|
||||
"/*" ( ~[\*] | Asterisk )* "*/" -> Comment
|
||||
[\*] -> Asterisk
|
||||
lexical restrictions
|
||||
Asterisk -/- [\/]
|
||||
context-free restrictions
|
||||
LAYOUT? -/- [\ \t\n] | [\#]
|
||||
syntax
|
||||
HashComment <START> -> <START>
|
76
src/fix-ng/parser.cc
Normal file
76
src/fix-ng/parser.cc
Normal file
|
@ -0,0 +1,76 @@
|
|||
extern "C" {
|
||||
#include <sglr.h>
|
||||
#include <asfix2.h>
|
||||
}
|
||||
|
||||
#include "parser.hh"
|
||||
#include "shared.hh"
|
||||
#include "expr.hh"
|
||||
#include "parse-table.h"
|
||||
|
||||
|
||||
Expr parseExprFromFile(const Path & path)
|
||||
{
|
||||
/* Perhaps this is already an imploded parse tree? */
|
||||
Expr e = ATreadFromNamedFile(path.c_str());
|
||||
if (e) return e;
|
||||
|
||||
/* Initialise the SDF libraries. */
|
||||
static bool initialised = false;
|
||||
static ATerm parseTable = 0;
|
||||
static language lang = 0;
|
||||
|
||||
if (!initialised) {
|
||||
PT_initMEPTApi();
|
||||
PT_initAsFix2Api();
|
||||
SGinitParser(ATfalse);
|
||||
|
||||
ATprotect(&parseTable);
|
||||
parseTable = ATreadFromBinaryString(
|
||||
(char *) fixParseTable, sizeof fixParseTable);
|
||||
if (!parseTable)
|
||||
throw Error(format("cannot construct parse table term"));
|
||||
|
||||
ATprotect(&lang);
|
||||
lang = ATmake("Fix");
|
||||
if (!SGopenLanguageFromTerm(
|
||||
(char *) programId.c_str(), lang, parseTable))
|
||||
throw Error(format("cannot open language"));
|
||||
|
||||
SG_STARTSYMBOL_ON();
|
||||
SG_OUTPUT_ON();
|
||||
SG_ASFIX2ME_ON();
|
||||
SG_AMBIGUITY_ERROR_ON();
|
||||
|
||||
initialised = true;
|
||||
}
|
||||
|
||||
ATerm result = SGparseFile((char *) programId.c_str(), lang,
|
||||
"Expr", (char *) path.c_str());
|
||||
if (!result)
|
||||
throw SysError(format("parse failed in `%1%'") % path);
|
||||
if (SGisParseError(result))
|
||||
throw Error(format("parse error in `%1%': %2%")
|
||||
% path % printTerm(result));
|
||||
|
||||
PT_ParseTree tree = PT_makeParseTreeFromTerm(result);
|
||||
if (!tree)
|
||||
throw Error(format("cannot create parse tree"));
|
||||
|
||||
ATerm imploded = PT_implodeParseTree(tree,
|
||||
ATtrue,
|
||||
ATtrue,
|
||||
ATtrue,
|
||||
ATtrue,
|
||||
ATtrue,
|
||||
ATtrue,
|
||||
ATfalse,
|
||||
ATtrue,
|
||||
ATtrue,
|
||||
ATtrue,
|
||||
ATfalse);
|
||||
if (!imploded)
|
||||
throw Error(format("cannot implode parse tree"));
|
||||
|
||||
return imploded;
|
||||
}
|
15
src/fix-ng/parser.hh
Normal file
15
src/fix-ng/parser.hh
Normal file
|
@ -0,0 +1,15 @@
|
|||
#ifndef __PARSER_H
|
||||
#define __PARSER_H
|
||||
|
||||
#include <string>
|
||||
#include <aterm2.h>
|
||||
|
||||
#include "util.hh"
|
||||
|
||||
|
||||
typedef ATerm Expr;
|
||||
|
||||
Expr parseExprFromFile(const Path & path);
|
||||
|
||||
|
||||
#endif /* !__PARSER_H */
|
Loading…
Reference in a new issue