--- /dev/null
+#include "labels.hh"
+#include "compatibility.hh"
+
+//=========================== PATHNAME ===============================
+
+/**
+ * Grammar for labels with pathnames
+ *-----------------------------------
+ * <label> = <name> | <path> <name>
+ * <name> = [^/]+
+ * <path> = <apath> | <rpath>
+ * <apath> = '/' | '/' <rpath>
+ * <rpath> = (<gname> '/')+
+ * <gname> = ".." | "." | <gtype> <name>
+ * <gtype> = "h:" | "H:" | "v:" | V:" | "t:" | "T:"
+ *
+ */
+
+Sym PATHROOT = symbol ("/");
+Tree pathRoot() { return tree(PATHROOT); }
+bool isPathRoot(Tree t) { return isTree(t, PATHROOT); }
+
+Sym PATHPARENT = symbol ("..");
+Tree pathParent() { return tree(PATHPARENT); }
+bool isPathParent(Tree t) { return isTree(t, PATHPARENT); }
+
+Sym PATHCURRENT = symbol (".");
+Tree pathCurrent() { return tree(PATHCURRENT); }
+bool isPathCurrent(Tree t) { return isTree(t, PATHCURRENT); }
+
+
+
+/**
+ * analyze name for "H:name" | "V:name" etc
+ */
+
+static Tree encodeName(char g, const string& name)
+{
+ switch (g) {
+ case 'v':
+ case 'V': return cons(tree(0), tree(name));
+
+ case 'h':
+ case 'H': return cons(tree(1), tree(name));
+
+ case 't':
+ case 'T': return cons(tree(2), tree(name));
+
+ default : return cons(tree(0), tree(name));
+ }
+}
+
+
+/**
+ * Analyzes a label and converts it as a path
+ */
+
+static Tree label2path(const char* label)
+{
+ if (label[0] == 0) {
+ return cons(tree(""), nil);
+
+ } else if (label[0] == '/') {
+ return cons(pathRoot(), label2path(&label[1]));
+
+ } else if ((label[0] == '.') && (label[1] == '/')) {
+ return label2path(&label[2]);
+
+ } else if ((label[0] == '.') && (label[1] == '.') && (label[2] == '/')) {
+ return cons(pathParent(), label2path(&label[3]));
+
+ } else if (label[1] == ':') {
+ char g = label[0];
+ string s;
+ int i = 2;
+ while ((label[i] != 0) && (label[i] != '/')) {
+ s.push_back(label[i]);
+ i++;
+ }
+ if (label[i] == '/') i++;
+ return cons(encodeName(g,s), label2path(&label[i]));
+
+ } else {
+ return cons(tree(label),nil);
+ }
+}
+
+
+/**
+ * Concatenate the relative path to the absolute path
+ * Note that the relpath is top-down while the abspath
+ * is bottom-up
+ */
+
+static Tree concatPath(Tree relpath, Tree abspath)
+{
+ if (isList(relpath)) {
+ Tree head = hd(relpath);
+ if (isPathRoot(head)) {
+ return concatPath(tl(relpath), nil);
+ } else if (isPathParent(head)) {
+ if (!isList(abspath)) {
+ //cerr << "abspath : " << *abspath << endl;
+ return concatPath(tl(relpath), hd(relpath));
+ } else {
+ return concatPath(tl(relpath), tl(abspath));
+ }
+ } else if (isPathCurrent(head)) {
+ return concatPath(tl(relpath), abspath);
+ } else {
+ return concatPath(tl(relpath), cons(head,abspath));
+ }
+ } else {
+ assert(isNil(relpath));
+ return abspath;
+ }
+}
+
+
+static Tree normalizeLabel(Tree label, Tree path)
+{
+ // we suppose label = "../label" ou "name/label" ou "name"
+ //cout << "Normalize Label " << *label << " with path " << *path << endl;
+ if (isList(label)) {
+ return cons(label, path);
+ } else {
+ Sym s;
+ assert (isSym(label->node(),&s));
+ return concatPath(label2path(name(s)),path);
+ }
+}
+
+Tree normalizePath(Tree path)
+{
+ //cout << "Normalize Path [[" << *path << "]]" << endl;
+ Tree npath;
+ if (isNil(path)) {
+ npath = path;
+ } else {
+ npath = normalizeLabel(hd(path), normalizePath(tl(path)));
+ }
+ //cout << " -> [[" << *npath << "]]" << endl;
+ return npath;
+}
+