From 3b3b77291a21ed23a2763c79335501beebb10746 Mon Sep 17 00:00:00 2001
From: Niels Moseley <n.a.moseley@moseleyinstruments.com>
Date: Sun, 24 Mar 2019 22:54:18 +0100
Subject: [PATCH 1/3] Updated the liberty parser to accept [A:B] ranges (AST
 has not been updated). Liberty parser now also accepts key : value pair lines
 that do not end in ';'.

---
 passes/techmap/libparse.cc       |  87 +++++++-
 passes/techmap/libparse.h        |  10 +-
 tests/liberty/.gitignore         |   2 +
 tests/liberty/busdef.lib         |  81 +++++++
 tests/liberty/normal.lib         | 360 +++++++++++++++++++++++++++++++
 tests/liberty/run-test.sh        |  10 +
 tests/liberty/semicolmissing.lib |  72 +++++++
 tests/liberty/small.v            |  16 ++
 8 files changed, 631 insertions(+), 7 deletions(-)
 create mode 100644 tests/liberty/.gitignore
 create mode 100644 tests/liberty/busdef.lib
 create mode 100644 tests/liberty/normal.lib
 create mode 100755 tests/liberty/run-test.sh
 create mode 100644 tests/liberty/semicolmissing.lib
 create mode 100644 tests/liberty/small.v

diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc
index 3927a657b..878ca3160 100644
--- a/passes/techmap/libparse.cc
+++ b/passes/techmap/libparse.cc
@@ -24,6 +24,7 @@
 #include <istream>
 #include <fstream>
 #include <iostream>
+#include <sstream>
 
 #ifndef FILTERLIB
 #include "kernel/log.h"
@@ -86,15 +87,17 @@ int LibertyParser::lexer(std::string &str)
 {
 	int c;
 
+    // eat whitespace
 	do {
 		c = f.get();
 	} while (c == ' ' || c == '\t' || c == '\r');
 
-	if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.' || c == '[' || c == ']') {
+    // search for identifiers, numbers, plus or minus.
+	if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.') {
 		str = c;
 		while (1) {
 			c = f.get();
-			if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.' || c == '[' || c == ']')
+			if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.')
 				str += c;
 			else
 				break;
@@ -111,6 +114,8 @@ int LibertyParser::lexer(std::string &str)
 		}
 	}
 
+    // if it wasn't an identifer, number of array range,
+    // maybe it's a string?
 	if (c == '"') {
 		str = "";
 		while (1) {
@@ -125,9 +130,10 @@ int LibertyParser::lexer(std::string &str)
 		return 'v';
 	}
 
+    // if it wasn't a string, perhaps it's a comment or a forward slash?
 	if (c == '/') {
 		c = f.get();
-		if (c == '*') {
+		if (c == '*') {         // start of '/*' block comment
 			int last_c = 0;
 			while (c > 0 && (last_c != '*' || c != '/')) {
 				last_c = c;
@@ -136,7 +142,7 @@ int LibertyParser::lexer(std::string &str)
 					line++;
 			}
 			return lexer(str);
-		} else if (c == '/') {
+		} else if (c == '/') {  // start of '//' line comment
 			while (c > 0 && c != '\n')
 				c = f.get();
 			line++;
@@ -144,9 +150,10 @@ int LibertyParser::lexer(std::string &str)
 		}
 		f.unget();
 		// fprintf(stderr, "LEX: char >>/<<\n");
-		return '/';
+		return '/';             // a single '/' charater.
 	}
 
+    // check for a backslash
 	if (c == '\\') {
 		c = f.get();
 		if (c == '\r')
@@ -157,11 +164,15 @@ int LibertyParser::lexer(std::string &str)
 		return '\\';
 	}
 
+    // check for a new line
 	if (c == '\n') {
 		line++;
 		return 'n';
 	}
 
+    // anything else, such as ';' will get passed
+    // through as literal items.
+
 	// if (c >= 32 && c < 255)
 	// 	fprintf(stderr, "LEX: char >>%c<<\n", c);
 	// else
@@ -210,7 +221,12 @@ LibertyAst *LibertyParser::parse()
 				ast->value += str;
 				tok = lexer(str);
 			}
-			if (tok == ';')
+            
+            // In a liberty file, all key : value pairs should end in ';'
+            // However, there are some liberty files in the wild that
+            // just have a newline. We'll be kind and accept a newline
+            // instead of the ';' too..
+			if ((tok == ';') || (tok == 'n'))
 				break;
 			else
 				error();
@@ -225,6 +241,48 @@ LibertyAst *LibertyParser::parse()
 					continue;
 				if (tok == ')')
 					break;
+                
+                // FIXME: the AST needs to be extended to store
+                //        these vector ranges.
+                if (tok == '[')
+                {
+                    // parse vector range [A] or [A:B]
+                    std::string arg;
+                    tok = lexer(arg);
+                    if (tok != 'v')
+                    {
+                        // expected a vector array index
+                        error("Expected a number.");
+                    }
+                    else
+                    {
+                        // fixme: check for number A
+                    }
+                    tok = lexer(arg);
+                    // optionally check for : in case of [A:B]
+                    // if it isn't we just expect ']'
+                    // as we have [A]
+                    if (tok == ':')
+                    {
+                        tok = lexer(arg);
+                        if (tok != 'v')
+                        {
+                            // expected a vector array index
+                            error("Expected a number.");
+                        }
+                        else
+                        {
+                            // fixme: check for number B
+                            tok = lexer(arg);                            
+                        }
+                    }
+                    // expect a closing bracket of array range
+                    if (tok != ']')
+                    {
+                        error("Expected ']' on array range.");
+                    }
+                    continue;           
+                }
 				if (tok != 'v')
 					error();
 				ast->args.push_back(arg);
@@ -255,6 +313,14 @@ void LibertyParser::error()
 	log_error("Syntax error in liberty file on line %d.\n", line);
 }
 
+void LibertyParser::error(const std::string &str)
+{
+    std::stringstream ss;
+    ss << "Syntax error in liberty file on line " << line << ".\n";
+    ss << "  " << str << "\n";
+    log_error("%s", ss.str().c_str());
+}
+
 #else
 
 void LibertyParser::error()
@@ -263,6 +329,15 @@ void LibertyParser::error()
 	exit(1);
 }
 
+void LibertyParser::error(const std::string &str)
+{
+    std::stringstream ss;
+    ss << "Syntax error in liberty file on line " << line << ".\n";
+    ss << "  " << str << "\n";
+    printf("%s", ss.str().c_str());
+    exit(1);
+}
+
 /**** BEGIN: http://svn.clifford.at/tools/trunk/examples/check.h ****/
 
 #define CHECK_NV(result, check)                                      \
diff --git a/passes/techmap/libparse.h b/passes/techmap/libparse.h
index cf6325570..c9ebd06c5 100644
--- a/passes/techmap/libparse.h
+++ b/passes/techmap/libparse.h
@@ -46,9 +46,17 @@ namespace Yosys
 		LibertyAst *ast;
 		LibertyParser(std::istream &f) : f(f), line(1), ast(parse()) {}
 		~LibertyParser() { if (ast) delete ast; }
+        
+        /* lexer return values:
+           'v': identifier, string, array range [...] -> str holds the token string
+           'n': newline
+           anything else is a single character.
+        */
 		int lexer(std::string &str);
-		LibertyAst *parse();
+		
+        LibertyAst *parse();
 		void error();
+        void error(const std::string &str);
 	};
 }
 
diff --git a/tests/liberty/.gitignore b/tests/liberty/.gitignore
new file mode 100644
index 000000000..e6ec49c4a
--- /dev/null
+++ b/tests/liberty/.gitignore
@@ -0,0 +1,2 @@
+*.log
+test.ys
diff --git a/tests/liberty/busdef.lib b/tests/liberty/busdef.lib
new file mode 100644
index 000000000..b5e3d50b9
--- /dev/null
+++ b/tests/liberty/busdef.lib
@@ -0,0 +1,81 @@
+/********************************************/
+/*                                          */
+/* Supergate cell library for Bench marking */
+/*                                          */
+/* Symbiotic EDA GmbH / Moseley Instruments */
+/* Niels A. Moseley                         */
+/*                                          */
+/* Process: none                            */
+/*                                          */
+/* Date   : 02-11-2018                      */
+/* Version: 1.0                             */
+/*                                          */
+/********************************************/
+
+library(supergate) {
+  technology (cmos);
+  revision : 1.0;
+  
+  time_unit                     : "1ps";
+  pulling_resistance_unit       : "1kohm";  
+  voltage_unit                  : "1V";
+  current_unit                  : "1uA";  
+  
+  capacitive_load_unit(1,ff);
+  
+  default_inout_pin_cap         :  7.0;
+  default_input_pin_cap         :  7.0;
+  default_output_pin_cap        :  0.0;
+  default_fanout_load           :  1.0;
+
+  default_wire_load_capacitance : 0.1;
+  default_wire_load_resistance  : 1.0e-3;
+  default_wire_load_area        : 0.0;
+
+  nom_process                   :  1.0;
+  nom_temperature               : 25.0;
+  nom_voltage                   :  1.2;
+  
+  delay_model                   : generic_cmos;
+  
+    type( IO_bus_3_to_0 ) {
+        base_type : array ;
+        data_type : bit ;
+        bit_width : 4;
+        bit_from : 3 ;
+        bit_to : 0 ;
+        downto : true ;
+    }
+
+    cell (SRAM) {
+        area : 1 ;
+        memory() {
+            type : ram;
+            address_width : 4;
+            word_width : 4;
+        }
+        pin(CE1) {
+            direction : input;
+            capacitance : 0.021;
+            max_transition : 1.024;
+            switch_pin : true;
+        }
+        bus(I1)  {
+            bus_type : IO_bus_3_to_0 ;
+            direction : input;
+            pin (I1[3:0]) {
+                timing() {
+                    related_pin :   "CE1" ;
+                    timing_type : setup_rising ;
+                    rise_constraint (scalar) {
+                        values("0.0507786");
+                    }
+                    fall_constraint (scalar) {
+                        values("0.0507786");
+                    }
+                }
+            }
+        }
+    }
+
+} /* end */
diff --git a/tests/liberty/normal.lib b/tests/liberty/normal.lib
new file mode 100644
index 000000000..1474e2b59
--- /dev/null
+++ b/tests/liberty/normal.lib
@@ -0,0 +1,360 @@
+/********************************************/
+/*                                          */
+/* Supergate cell library for Bench marking */
+/*                                          */
+/* Symbiotic EDA GmbH / Moseley Instruments */
+/* Niels A. Moseley                         */
+/*                                          */
+/* Process: none                            */
+/*                                          */
+/* Date   : 02-11-2018                      */
+/* Version: 1.0                             */
+/*                                          */
+/********************************************/
+
+library(supergate) {
+  technology (cmos);
+  revision : 1.0;
+  
+  time_unit                     : "1ps";
+  pulling_resistance_unit       : "1kohm";  
+  voltage_unit                  : "1V";
+  current_unit                  : "1uA";  
+  
+  capacitive_load_unit(1,ff);
+  
+  default_inout_pin_cap         :  7.0;
+  default_input_pin_cap         :  7.0;
+  default_output_pin_cap        :  0.0;
+  default_fanout_load           :  1.0;
+
+  default_wire_load_capacitance : 0.1;
+  default_wire_load_resistance  : 1.0e-3;
+  default_wire_load_area        : 0.0;
+
+  nom_process                   :  1.0;
+  nom_temperature               : 25.0;
+  nom_voltage                   :  1.2;
+  
+  delay_model                   : generic_cmos;
+  
+  /* Inverter */
+  cell (inv) {
+    area : 1;
+    pin(A) {
+      direction : input;
+    }
+    
+    pin(Y) {
+      direction : output;
+      function : "A'";
+    }
+  }
+  
+  /* tri-state inverter */
+  cell (tri_inv) {
+    area : 4;
+    pin(A) {
+      direction : input;    
+    }
+    pin(S) {
+      direction : input;
+    }
+    pin(Z) {
+      direction : output;
+      function  : "A'";
+      three_State : "S'";
+    }
+  }
+  
+  cell (buffer) {
+    area : 5;
+    pin(A) {
+      direction : input;
+    }
+    pin(Y) {
+      direction : output;
+      function : "A";
+    }
+  }  
+  
+  /* 2-input NAND gate */
+  cell (nand2) {
+    area : 3;
+    pin(A) {
+      direction : input;
+    }
+    pin(B) {
+      direction : input;
+    }
+    pin(Y) {
+      direction: output;
+      function : "(A * B)'";
+    }
+  }
+  
+  /* 2-input NOR gate */
+  cell (nor2) {
+    area : 3;
+    pin(A) {
+      direction : input;
+    }
+    pin(B) {
+      direction : input;
+    }
+    pin(Y) {
+      direction: output;
+      function : "(A + B)'";
+    }
+  }
+  
+  /* 2-input XOR */
+  cell (xor2) {
+    area : 6;
+    pin(A) {
+      direction : input;
+    }
+    pin(B) {
+      direction : input;
+    }
+    pin(Y) {
+      direction: output;
+      function : "(A *B') + (A' * B)";
+    }
+  }
+  
+  /* 2-input inverting MUX */
+  cell (imux2) {
+    area : 5;
+    pin(A) {
+      direction : input;
+    }
+    pin(B) {
+      direction : input;
+    }
+    pin(S) {
+      direction : input;
+    } 
+    pin(Y) {
+      direction: output;
+      function : "( (A * S) + (B * S') )'";
+    }
+  }
+  
+  /* D-type flip-flop with asynchronous reset and preset */
+  cell (dff) 
+  {
+    area : 6;
+    ff("IQ", "IQN") {
+      next_state : "D";
+      clocked_on : "CLK";
+      clear      : "RESET";
+      preset     : "PRESET";
+      clear_preset_var1 : L;
+      clear_preset_var2 : L;
+    } 
+    pin(D) {
+      direction : input;
+    }
+    pin(CLK) {
+      direction : input;
+    }
+    pin(RESET) {
+      direction : input;
+    }
+    pin(PRESET) {
+      direction : input;
+    }
+    pin(Q) {
+      direction: output;
+      function : "IQ";
+      timing() {
+        timing_type : rising_edge;
+        intrinsic_rise : 65;
+        intrinsic_fall : 65;
+        rise_resistance : 0;
+        fall_resistance : 0; 
+        related_pin : "CLK";
+      }
+      timing () {
+        timing_type : clear;
+        timing_sense : positive_unate;
+        intrinsic_fall : 75;
+        related_pin : "RESET";
+      }
+      timing () {
+        timing_type : preset;
+        timing_sense : negative_unate;
+        intrinsic_rise : 75;
+        related_pin : "PRESET";
+      }      
+    }
+    pin(QN) {
+      direction: output;
+      function : "IQN";
+      timing() {
+        timing_type : rising_edge;
+        intrinsic_rise : 65;
+        intrinsic_fall : 65;
+        rise_resistance : 0;
+        fall_resistance : 0; 
+        related_pin : "CLK";
+      }
+      timing () {
+        timing_type : preset;
+        timing_sense : negative_unate;
+        intrinsic_rise : 75;
+        related_pin : "RESET";
+      }
+      timing () {
+        timing_type : clear;
+        timing_sense : positive_unate;
+        intrinsic_fall : 75;
+        related_pin : "PRESET";
+      }      
+    } 
+  }
+
+  /* Latch */
+  cell(latch) {
+    area : 5;
+    latch ("IQ","IQN") {
+      enable : "G";
+      data_in : "D";
+    }
+
+    pin(D) {
+      direction : input;
+    }
+    pin(G) {
+      direction : input;
+    }
+ 
+    pin(Q) {
+      direction : output;
+      function : "IQ";
+      internal_node : "Q";
+      
+      timing() {
+        timing_type : rising_edge;
+        intrinsic_rise : 65;
+        intrinsic_fall : 65;
+        rise_resistance : 0;
+        fall_resistance : 0;
+        related_pin : "G";
+      }
+      
+      timing() {
+        timing_sense : positive_unate;
+        intrinsic_rise : 65;
+        intrinsic_fall : 65;
+        rise_resistance : 0;
+        fall_resistance : 0;
+        related_pin : "D";
+      }
+    }
+    
+    pin(QN) {
+      direction : output;
+      function : "IQN";
+      internal_node : "QN";
+      
+      timing() {
+        timing_type : rising_edge;
+        intrinsic_rise : 65;
+        intrinsic_fall : 65;
+        rise_resistance : 0;
+        fall_resistance : 0;
+        related_pin : "G";
+      }
+      
+      timing() {
+        timing_sense : negative_unate;
+        intrinsic_rise : 65;
+        intrinsic_fall : 65;
+        rise_resistance : 0;
+        fall_resistance : 0;
+        related_pin : "D";
+      }
+    }
+  }
+
+  /* 3 input AND-OR-INVERT gate */
+  cell (aoi211) {
+    area : 3;
+    pin(A) {
+      direction : input;
+    }
+    pin(B) {
+      direction : input;
+    }
+    pin(C) {
+      direction : input;
+    }    
+    pin(Y) {
+      direction: output;
+      function : "((A * B) + C)'";
+    }
+  }
+
+
+  /* 3 input OR-AND-INVERT gate */
+  cell (oai211) {
+    area : 3;
+    pin(A) {
+      direction : input;
+    }
+    pin(B) {
+      direction : input;
+    }
+    pin(C) {
+      direction : input;
+    }    
+    pin(Y) {
+      direction: output;
+      function : "((A + B) * C)'";
+    }
+  }
+
+  /* half adder */
+  cell (halfadder) {
+    area : 5;
+    pin(A) {
+      direction : input;
+    }
+    pin(B) {
+      direction : input;
+    }
+    pin(C) {
+      direction : output;
+      function  : "(A * B)";
+    }    
+    pin(Y) {
+      direction: output;
+      function : "(A *B') + (A' * B)";
+    }    
+  }
+
+  /* full adder */
+  cell (fulladder) {
+    area : 8;
+    pin(A) {
+      direction : input;
+    }
+    pin(B) {
+      direction : input;
+    }
+    pin(CI) {
+      direction : input;
+    }    
+    pin(CO) {
+      direction : output;
+      function : "(((A * B)+(B * CI))+(CI * A))";
+    }
+    pin(Y) {
+      direction: output;
+      function : "((A^B)^CI)";
+    }    
+  }
+
+} /* end */
diff --git a/tests/liberty/run-test.sh b/tests/liberty/run-test.sh
new file mode 100755
index 000000000..7e2ed2370
--- /dev/null
+++ b/tests/liberty/run-test.sh
@@ -0,0 +1,10 @@
+#!/bin/bash
+set -e
+
+for x in *.lib; do
+	echo "Running $x.."
+    echo "read_verilog small.v" > test.ys
+    echo "synth -top small" >> test.ys
+    echo "dfflibmap -liberty ${x}" >> test.ys
+	../../yosys -ql ${x%.lib}.log -s test.ys
+done
diff --git a/tests/liberty/semicolmissing.lib b/tests/liberty/semicolmissing.lib
new file mode 100644
index 000000000..f7c20750a
--- /dev/null
+++ b/tests/liberty/semicolmissing.lib
@@ -0,0 +1,72 @@
+/********************************************/
+/*                                          */
+/* Supergate cell library for Bench marking */
+/*                                          */
+/* Symbiotic EDA GmbH / Moseley Instruments */
+/* Niels A. Moseley                         */
+/*                                          */
+/* Process: none                            */
+/*                                          */
+/* Date   : 24-03-2019                      */
+/* Version: 1.0                             */
+/* Version: 1.1 - Removed semicolons in     */
+/*                full adder                */
+/*                                          */
+/********************************************/
+
+/* 
+    semi colon is missing in full-adder specification
+    some TSMC liberty files are formatted this way..
+*/
+
+library(supergate) {
+  technology (cmos);
+  revision : 1.0;
+  
+  time_unit                     : "1ps";
+  pulling_resistance_unit       : "1kohm";  
+  voltage_unit                  : "1V";
+  current_unit                  : "1uA";  
+  
+  capacitive_load_unit(1,ff);
+  
+  default_inout_pin_cap         :  7.0;
+  default_input_pin_cap         :  7.0;
+  default_output_pin_cap        :  0.0;
+  default_fanout_load           :  1.0;
+
+  default_wire_load_capacitance : 0.1;
+  default_wire_load_resistance  : 1.0e-3;
+  default_wire_load_area        : 0.0;
+
+  nom_process                   :  1.0;
+  nom_temperature               : 25.0;
+  nom_voltage                   :  1.2;
+  
+  delay_model                   : generic_cmos;
+  
+  /* full adder */
+  cell (fulladder) {
+    area : 8
+    pin(A) {
+      direction : input
+    }
+    pin(B) {
+      direction : input
+    }
+    pin(CI) {
+      direction : input
+    }    
+    pin(CO) {
+      direction : output
+      function : "(((A * B)+(B * CI))+(CI * A))"
+    }
+    pin(Y) {
+      direction: output
+      function : "((A^B)^CI)"
+    }    
+  }
+
+} /* end */
+
+
diff --git a/tests/liberty/small.v b/tests/liberty/small.v
new file mode 100644
index 000000000..bd94be4fc
--- /dev/null
+++ b/tests/liberty/small.v
@@ -0,0 +1,16 @@
+/** small, meaningless design to test loading of liberty files */
+
+module small
+(
+    input clk,
+    output reg[7:0] count
+);
+
+initial count = 0;
+
+always @ (posedge clk) 
+begin
+    count <= count + 1'b1;
+end
+
+endmodule

From 9d9cc8a3140cdbc2d976a5b06b5a057845da739a Mon Sep 17 00:00:00 2001
From: Niels Moseley <n.a.moseley@moseleyinstruments.com>
Date: Mon, 25 Mar 2019 12:15:10 +0100
Subject: [PATCH 2/3] EOL is now accepted as ';' replacement on lines that look
 like: feature_xyz(option)

---
 passes/techmap/libparse.cc | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc
index 878ca3160..9dc3e96ab 100644
--- a/passes/techmap/libparse.cc
+++ b/passes/techmap/libparse.cc
@@ -202,12 +202,11 @@ LibertyAst *LibertyParser::parse()
 	{
 		tok = lexer(str);
 
-		if (tok == ';')
+        // allow both ';' and new lines to 
+        // terminate a statement.
+		if ((tok == ';') || (tok == 'n'))
 			break;
 
-		if (tok == 'n')
-			continue;
-
 		if (tok == ':' && ast->value.empty()) {
 			tok = lexer(ast->value);
 			if (tok != 'v')

From 1f7f54e68eb201976ddd42cb906492bf9e611030 Mon Sep 17 00:00:00 2001
From: Niels Moseley <n.a.moseley@moseleyinstruments.com>
Date: Mon, 25 Mar 2019 14:12:04 +0100
Subject: [PATCH 3/3] spaces -> tabs

---
 passes/techmap/libparse.cc | 156 ++++++++++++++++++-------------------
 1 file changed, 78 insertions(+), 78 deletions(-)

diff --git a/passes/techmap/libparse.cc b/passes/techmap/libparse.cc
index 9dc3e96ab..8eadd8735 100644
--- a/passes/techmap/libparse.cc
+++ b/passes/techmap/libparse.cc
@@ -87,12 +87,12 @@ int LibertyParser::lexer(std::string &str)
 {
 	int c;
 
-    // eat whitespace
+	// eat whitespace
 	do {
 		c = f.get();
 	} while (c == ' ' || c == '\t' || c == '\r');
 
-    // search for identifiers, numbers, plus or minus.
+	// search for identifiers, numbers, plus or minus.
 	if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_' || c == '-' || c == '+' || c == '.') {
 		str = c;
 		while (1) {
@@ -114,8 +114,8 @@ int LibertyParser::lexer(std::string &str)
 		}
 	}
 
-    // if it wasn't an identifer, number of array range,
-    // maybe it's a string?
+	// if it wasn't an identifer, number of array range,
+	// maybe it's a string?
 	if (c == '"') {
 		str = "";
 		while (1) {
@@ -130,7 +130,7 @@ int LibertyParser::lexer(std::string &str)
 		return 'v';
 	}
 
-    // if it wasn't a string, perhaps it's a comment or a forward slash?
+	// if it wasn't a string, perhaps it's a comment or a forward slash?
 	if (c == '/') {
 		c = f.get();
 		if (c == '*') {         // start of '/*' block comment
@@ -153,7 +153,7 @@ int LibertyParser::lexer(std::string &str)
 		return '/';             // a single '/' charater.
 	}
 
-    // check for a backslash
+	// check for a backslash
 	if (c == '\\') {
 		c = f.get();
 		if (c == '\r')
@@ -164,14 +164,14 @@ int LibertyParser::lexer(std::string &str)
 		return '\\';
 	}
 
-    // check for a new line
+	// check for a new line
 	if (c == '\n') {
 		line++;
 		return 'n';
 	}
 
-    // anything else, such as ';' will get passed
-    // through as literal items.
+	// anything else, such as ';' will get passed
+	// through as literal items.
 
 	// if (c >= 32 && c < 255)
 	// 	fprintf(stderr, "LEX: char >>%c<<\n", c);
@@ -202,8 +202,8 @@ LibertyAst *LibertyParser::parse()
 	{
 		tok = lexer(str);
 
-        // allow both ';' and new lines to 
-        // terminate a statement.
+		// allow both ';' and new lines to 
+		// terminate a statement.
 		if ((tok == ';') || (tok == 'n'))
 			break;
 
@@ -220,11 +220,11 @@ LibertyAst *LibertyParser::parse()
 				ast->value += str;
 				tok = lexer(str);
 			}
-            
-            // In a liberty file, all key : value pairs should end in ';'
-            // However, there are some liberty files in the wild that
-            // just have a newline. We'll be kind and accept a newline
-            // instead of the ';' too..
+			
+			// In a liberty file, all key : value pairs should end in ';'
+			// However, there are some liberty files in the wild that
+			// just have a newline. We'll be kind and accept a newline
+			// instead of the ';' too..
 			if ((tok == ';') || (tok == 'n'))
 				break;
 			else
@@ -240,48 +240,48 @@ LibertyAst *LibertyParser::parse()
 					continue;
 				if (tok == ')')
 					break;
-                
-                // FIXME: the AST needs to be extended to store
-                //        these vector ranges.
-                if (tok == '[')
-                {
-                    // parse vector range [A] or [A:B]
-                    std::string arg;
-                    tok = lexer(arg);
-                    if (tok != 'v')
-                    {
-                        // expected a vector array index
-                        error("Expected a number.");
-                    }
-                    else
-                    {
-                        // fixme: check for number A
-                    }
-                    tok = lexer(arg);
-                    // optionally check for : in case of [A:B]
-                    // if it isn't we just expect ']'
-                    // as we have [A]
-                    if (tok == ':')
-                    {
-                        tok = lexer(arg);
-                        if (tok != 'v')
-                        {
-                            // expected a vector array index
-                            error("Expected a number.");
-                        }
-                        else
-                        {
-                            // fixme: check for number B
-                            tok = lexer(arg);                            
-                        }
-                    }
-                    // expect a closing bracket of array range
-                    if (tok != ']')
-                    {
-                        error("Expected ']' on array range.");
-                    }
-                    continue;           
-                }
+				
+				// FIXME: the AST needs to be extended to store
+				//        these vector ranges.
+				if (tok == '[')
+				{
+					// parse vector range [A] or [A:B]
+					std::string arg;
+					tok = lexer(arg);
+					if (tok != 'v')
+					{
+						// expected a vector array index
+						error("Expected a number.");
+					}
+					else
+					{
+						// fixme: check for number A
+					}
+					tok = lexer(arg);
+					// optionally check for : in case of [A:B]
+					// if it isn't we just expect ']'
+					// as we have [A]
+					if (tok == ':')
+					{
+						tok = lexer(arg);
+						if (tok != 'v')
+						{
+							// expected a vector array index
+							error("Expected a number.");
+						}
+						else
+						{
+							// fixme: check for number B
+							tok = lexer(arg);                            
+						}
+					}
+					// expect a closing bracket of array range
+					if (tok != ']')
+					{
+						error("Expected ']' on array range.");
+					}
+					continue;           
+				}
 				if (tok != 'v')
 					error();
 				ast->args.push_back(arg);
@@ -314,10 +314,10 @@ void LibertyParser::error()
 
 void LibertyParser::error(const std::string &str)
 {
-    std::stringstream ss;
-    ss << "Syntax error in liberty file on line " << line << ".\n";
-    ss << "  " << str << "\n";
-    log_error("%s", ss.str().c_str());
+	std::stringstream ss;
+	ss << "Syntax error in liberty file on line " << line << ".\n";
+	ss << "  " << str << "\n";
+	log_error("%s", ss.str().c_str());
 }
 
 #else
@@ -330,32 +330,32 @@ void LibertyParser::error()
 
 void LibertyParser::error(const std::string &str)
 {
-    std::stringstream ss;
-    ss << "Syntax error in liberty file on line " << line << ".\n";
-    ss << "  " << str << "\n";
-    printf("%s", ss.str().c_str());
-    exit(1);
+	std::stringstream ss;
+	ss << "Syntax error in liberty file on line " << line << ".\n";
+	ss << "  " << str << "\n";
+	printf("%s", ss.str().c_str());
+	exit(1);
 }
 
 /**** BEGIN: http://svn.clifford.at/tools/trunk/examples/check.h ****/
 
 #define CHECK_NV(result, check)                                      \
    do {                                                              \
-     auto _R = (result);                                             \
-     if (!(_R check)) {                                              \
-       fprintf(stderr, "Error from '%s' (%ld %s) in %s:%d.\n",       \
-               #result, (long int)_R, #check, __FILE__, __LINE__);   \
-       abort();                                                      \
-     }                                                               \
+	 auto _R = (result);                                             \
+	 if (!(_R check)) {                                              \
+	   fprintf(stderr, "Error from '%s' (%ld %s) in %s:%d.\n",       \
+			   #result, (long int)_R, #check, __FILE__, __LINE__);   \
+	   abort();                                                      \
+	 }                                                               \
    } while(0)
 
 #define CHECK_COND(result)                                           \
    do {                                                              \
-     if (!(result)) {                                                \
-       fprintf(stderr, "Error from '%s' in %s:%d.\n",                \
-               #result, __FILE__, __LINE__);                         \
-       abort();                                                      \
-     }                                                               \
+	 if (!(result)) {                                                \
+	   fprintf(stderr, "Error from '%s' in %s:%d.\n",                \
+			   #result, __FILE__, __LINE__);                         \
+	   abort();                                                      \
+	 }                                                               \
    } while(0)
 
 /**** END: http://svn.clifford.at/tools/trunk/examples/check.h ****/