#!/usr/bin/perl
#
# Generalized schematic parsing.
#
# Input schematic should be opened on INPUT.
# We work by extracting an XML "token", then identifying
# it and calling the appropriate routine, essentially
# forming a top-down parser.
#
#
# Get the next "token".
$input = "";
sub nxt {
$input =~ s/^\s*//;
while ($input !~ /) {
$input .= || return "EOF";
$input =~ s/^\s*//;
}
while ($input !~ />/) {
$input .= || die "Premature EOF";
}
$input =~ s/^([^<]*)<([^>]*)>//;
($txt, $nxt) = ($1, $2);
return $nxt;
}
#
# Skip an uninteresting subsection.
# (This routine should be unused, if the parser is complete.)
sub skip {
local ($key) = @_;
print "Skipping $key...\n";
while (&nxt !~ /^\/$key\b/) {
last if $nxt =~ /^EOF$/;
}
return;
}
#
# Convert Eagle co-ordinates (in mm) to grid units per the
# LTSpice conventions.
# One silliness is that Eagle schematics normally render on
# a 1/10" grid, where LTSpice uses 16X of the finest grid.
# We therefore use 1 1/160" grid (25.4/160 == .15875).
# BEWARE -- The Y axis is upside down, but this function
# desn't know that.
$grid_unit = .15875; # default to 160 dpi.
sub grid_units {
return int($_[0]/$grid_unit);
}
# Snap component centers to the grid.
sub grid_snap {
local($gu) = @_;
return $gu if $gu == 0;
$gu = $gu/abs($gu)*int(abs($gu)/16+0.5)*16;
return $gu;
}
#
sub description {
while (&nxt) {
if ($nxt =~ /^\/description\b/) {
# $txt has the description
return;
} else {
die "Unrecognized: $nxt";
}
}
}
#
sub vertex {
return;
}
#
#
sub dimension {
# For now, treat as wire
die "x1: $nxt" unless $nxt =~ /\bx1="([^"]*)"/;
$x1 = &grid_units($1);
die "y1: $nxt" unless $nxt =~ /\by1="([^"]*)"/;
$y1 = -&grid_units($1);
die "x2: $nxt" unless $nxt =~ /\bx2="([^"]*)"/;
$x2 = &grid_units($1);
die "y2: $nxt" unless $nxt =~ /\by2="([^"]*)"/;
$y2 = -&grid_units($1);
die "width: $nxt" unless $nxt =~ /\bwidth="([^"]*)"/;
$width = $1;
die "layer: $nxt" unless $nxt =~ /\blayer="([^"]*)"/;
$layer = $1;
$style = "continuous";
$style = $1 if $nxt =~ /\bstyle="([^"]*)"/;
$style = "" if $style eq "continuous";
# BUGBUG: There should be a few other styles here.
$style = "1" if $style ne "";
$curve = "0";
$curve = $1 if $nxt =~ /\bcurve="([^"]*)"/;
$cap = "round";
$cap = $1 if $nxt =~ /\bcap="([^"]*)"/;
return;
}
#
sub polygon {
while (&nxt) {
if ($nxt =~ /^vertex\b/) {
&vertex();
} elsif ($nxt =~ /^\/polygon\b/) {
return;
} else {
die "Unrecognized: $nxt";
}
}
}
#
#
sub wire {
die "x1: $nxt" unless $nxt =~ /\bx1="([^"]*)"/;
$x1 = &grid_units($1);
die "y1: $nxt" unless $nxt =~ /\by1="([^"]*)"/;
$y1 = -&grid_units($1);
die "x2: $nxt" unless $nxt =~ /\bx2="([^"]*)"/;
$x2 = &grid_units($1);
die "y2: $nxt" unless $nxt =~ /\by2="([^"]*)"/;
$y2 = -&grid_units($1);
die "width: $nxt" unless $nxt =~ /\bwidth="([^"]*)"/;
$width = $1;
die "layer: $nxt" unless $nxt =~ /\blayer="([^"]*)"/;
$layer = $1;
$style = "continuous";
$style = $1 if $nxt =~ /\bstyle="([^"]*)"/;
$style = "" if $style eq "continuous";
# BUGBUG: There should be a few other styles here.
$style = "1" if $style ne "";
$curve = "0";
$curve = $1 if $nxt =~ /\bcurve="([^"]*)"/;
$cap = "round";
$cap = $1 if $nxt =~ /\bcap="([^"]*)"/;
return;
}
#
#
sub text {
die "x: $nxt" unless $nxt =~ /\bx="([^"]*)"/;
$x = &grid_units($1);
die "y: $nxt" unless $nxt =~ /\by="([^"]*)"/;
$y = -&grid_units($1);
die "size: $nxt" unless $nxt =~ /\bsize="([^"]*)"/;
$size = &grid_units($1);
$size = 4; # BUGBUG: Should calculate this!
die "layer: $nxt" unless $nxt =~ /\blayer="([^"]*)"/;
$layer = $1;
$font = "proportional";
$font = $1 if $nxt =~ /\bfont="([^"]*)"/;
$ratio = "8";
$ratio = $1 if $nxt =~ /\bratio="([^"]*)"/;
$rot = "R0";
$rot = $1 if $nxt =~ /\brot="([^"]*)"/;
$align = "bottom-left";
$align = $1 if $nxt =~ /\balign="([^"]*)"/;
$distance = "50";
$distance = $1 if $nxt =~ /\bdistance="([^"]*)"/;
while (&nxt) {
if ($nxt =~ /^\/text\b/) {
# $txt has the text
$txt =~ s/>/>/ig;
$txt =~ s/</
#
sub circle {
die "x: $nxt" unless $nxt =~ /\bx="([^"]*)"/;
$x = &grid_units($1);
die "y: $nxt" unless $nxt =~ /\by="([^"]*)"/;
$y = -&grid_units($1);
die "radius: $nxt" unless $nxt =~ /\bradius="([^"]*)"/;
$radius = &grid_units($1);
die "width: $nxt" unless $nxt =~ /\bwidth="([^"]*)"/;
$width = $1;
die "layer: $nxt" unless $nxt =~ /\blayer="([^"]*)"/;
$layer = $1;
return;
}
#
#
sub rectangle {
die "x1: $nxt" unless $nxt =~ /\bx1="([^"]*)"/;
$x1 = &grid_units($1);
die "y1: $nxt" unless $nxt =~ /\by1="([^"]*)"/;
$y1 = -&grid_units($1);
die "x2: $nxt" unless $nxt =~ /\bx2="([^"]*)"/;
$x2 = &grid_units($1);
die "y2: $nxt" unless $nxt =~ /\by2="([^"]*)"/;
$y2 = -&grid_units($1);
die "layer: $nxt" unless $nxt =~ /\blayer="([^"]*)"/;
$layer = $1;
$rot = "R0";
$rot = $1 if $nxt =~ /\brot="([^"]*)"/;
return;
}
#
#
sub frame {
die "x1: $nxt" unless $nxt =~ /\bx1="([^"]*)"/;
$x1 = &grid_units($1);
die "y1: $nxt" unless $nxt =~ /\by1="([^"]*)"/;
$y1 = -&grid_units($1);
die "x2: $nxt" unless $nxt =~ /\bx2="([^"]*)"/;
$x2 = &grid_units($1);
die "y2: $nxt" unless $nxt =~ /\by2="([^"]*)"/;
$y2 = -&grid_units($1);
die "columns: $nxt" unless $nxt =~ /\bcolumns="([^"]*)"/;
$columns = $1;
die "rows: $nxt" unless $nxt =~ /\brows="([^"]*)"/;
$rows = $1;
die "layer: $nxt" unless $nxt =~ /\blayer="([^"]*)"/;
$layer = $1;
$borderleft = "yes";
$borderleft = $1 if $nxt =~ /\bborder-left="([^"]*)"/;
$bordertop = "yes";
$bordertop = $1 if $nxt =~ /\bborder-top="([^"]*)"/;
$borderright = "yes";
$borderright = $1 if $nxt =~ /\bborder-right="([^"]*)"/;
$borderbottom = "yes";
$borderbottom = $1 if $nxt =~ /\bborder-bottom="([^"]*)"/;
return;
}
#
sub hole {
return;
}
#
sub pad {
return;
}
#
sub smd {
return;
}
#
sub package {
while (&nxt) {
if ($nxt =~ /^description\b/) {
&description();
} elsif ($nxt =~ /^polygon\b/) {
&polygon();
} elsif ($nxt =~ /^wire\b/) {
&wire();
} elsif ($nxt =~ /^text\b/) {
&text();
} elsif ($nxt =~ /^dimension\b/) {
&dimension();
} elsif ($nxt =~ /^circle\b/) {
&circle();
} elsif ($nxt =~ /^rectangle\b/) {
&rectangle();
} elsif ($nxt =~ /^frame\b/) {
&frame();
} elsif ($nxt =~ /^hole\b/) {
&hole();
} elsif ($nxt =~ /^pad\b/) {
&pad();
} elsif ($nxt =~ /^smd\b/) {
&smd();
} elsif ($nxt =~ /^\/package\b/) {
return;
} else {
die "Unrecognized: $nxt";
}
}
}
#
sub packages {
while (&nxt) {
if ($nxt =~ /^package\b/) {
&package();
} elsif ($nxt =~ /^\/packages\b/) {
return;
} else {
die "Unrecognized: $nxt";
}
}
}
#
#
sub pin {
die "name: $nxt" unless $nxt =~ /\bname="([^"]*)"/;
$name = $1;
die "x: $nxt" unless $nxt =~ /\bx="([^"]*)"/;
$x = &grid_units($1);
die "y: $nxt" unless $nxt =~ /\by="([^"]*)"/;
$y = -&grid_units($1);
$visible = "both";
$visible = $1 if $nxt =~ /\bvisible="([^"]*)"/;
$length = "long";
$length = $1 if $nxt =~ /\blength="([^"]*)"/;
$direction = "io";
$direction = $1 if $nxt =~ /\bdirection="([^"]*)"/;
$function = "none";
$function = $1 if $nxt =~ /\bfunction="([^"]*)"/;
$swaplevel = "0";
$swaplevel = $1 if $nxt =~ /\bswaplevel="([^"]*)"/;
$rot = "R0";
$rot = $1 if $nxt =~ /\brot="([^"]*)"/;
return;
}
#
# Add a tail for the pin
sub drawpin {
local($x, $y, $length, $function, $rot) = @_;
$scale = 32;
$scale = 0 if $length eq "point";
$scale = 16 if $length eq "short";
$scale = 48 if $length eq "long";
$scale = -$scale if $rot =~ s/^M//;
die "angle: $rot" unless $rot =~ /^R(\d+)/;
$angle = $1;
$x1 = $y1 = 0;
$x1 = 1 if $angle == 0;
$y1 = 1 if $angle == 90;
$x1 = -1 if $angle == 180;
$y1 = -1 if $angle == 270;
$x2 = int($x + $x1*$scale);
$y2 = int($y - $y1*$scale);
$symdraw .= "LINE Normal $x $y $x2 $y2\n";
if ($visible ne "off") {
$y -= 8;
$symdraw .= "WINDOW 123 $x $y Right 2\n";
}
if ($function eq "none") {
return;
} elsif ($function eq "dot") {
$x2 -= $x1/2;
$y2 += $y1/2;
$x1 = $x2 - $x1;
$y1 = $y2 - $y1;
warn "GOT HERE";
$symdraw .= "CIRCLE Normal $x1 $x2 $x2 $y2\n";
} else {
die "drawpin function: $function";
}
}
#
#
sub symbol {
die "symbol name: $nxt" unless $nxt =~ /\bname="([^"]*)"/;
$symbol = $1;
$symdraw = $sympins = "";
$order = 0;
while (&nxt) {
if ($nxt =~ /^description\b/) {
&description();
} elsif ($nxt =~ /^polygon\b/) {
die "polygon: $nxt";
&polygon();
} elsif ($nxt =~ /^wire\b/) {
&wire();
# Add a drawing command for a symbol.
$symdraw .= "LINE Normal $x1 $y1 $x2 $y2\n";
} elsif ($nxt =~ /^text\b/) {
&text();
# Replace >Name, >Value, etc.
$txt =~ s/>/>/ig;
if ($txt =~ />Name/i) {
$symdraw .= "WINDOW 0 $x $y Left 2\n";
} elsif ($txt =~ />Value/i) {
$symdraw .= "WINDOW 3 $x $y Left 2\n";
} elsif ($txt =~ />Drawing_Name/i) {
$symdraw .= "TEXT $x $y Left $size $f\n";
} elsif ($txt =~ />Last_Date_Time/i) {
$txt = localtime(time());
$symdraw .= "TEXT $x $y Left $size $txt\n";
# $symdraw .= "WINDOW 201 $x $y Left 2\n";
} elsif ($txt =~ />Sheet/i) {
# Kludge: Use Value to pass Sheet number to DOCFIELD
$symdraw .= "WINDOW 3 $x $y Left 2\n";
} else {
$symdraw .= "TEXT $x $y Left $size $txt\n" if $layer == 94;
}
} elsif ($nxt =~ /^dimension\b/) {
&dimension();
} elsif ($nxt =~ /^pin\b/) {
&pin();
# Draw the tail, etc. for the pin.
$pinx{$symbol} = $x;
$piny{$symbol} = $y;
&drawpin($x, $y, $length, $function, $rot);
# Kludge extra pin for EDGE-RIGHT.
if ($symbol =~ /^EDGE-/) {
$name = "1";
$sympins .= "PIN $x $y $function 0\n";
$sympins .= "PINATTR PinName $name\n";
++$order;
$name = "2";
$x -= 32;
}
# Place and name the pin.
$sympins .= "PIN $x $y $function 0\n";
$sympins .= "PINATTR PinName $name\n";
++$order;
# Don't guess SpiceOrder
# $sympins .= "PINATTR SpiceOrder $order\n";
} elsif ($nxt =~ /^circle\b/) {
&circle();
$x2 = int($x + $radius);
$y2 = int($y + $radius);
$x1 = $x - $radius;
$y1 = $y - $radius;
} elsif ($nxt =~ /^rectangle\b/) {
&rectangle();
warn "rotated rectangle: $rot" unless $rot eq "R0";
$symdraw .= "RECTANGLE Normal $x1 $y1 $x2 $y2\n"
unless $symbol =~ /^EDGE-/
} elsif ($nxt =~ /^frame\b/) {
&frame();
$symdraw .= "LINE Normal $x1 $y1 $x1 $y2\n";
$symdraw .= "LINE Normal $x1 $y2 $x2 $y2\n";
$symdraw .= "LINE Normal $x2 $y2 $x2 $y1\n";
$symdraw .= "LINE Normal $x2 $y1 $x1 $y1\n";
warn "borderleft labels omitted" unless $borderleft eq "no";
warn "bordertop labels omitted" unless $bordertop eq "no";
warn "borderright labels omitted" unless $borderright eq "no";
warn "borderbottom labels omitted" unless $borderbottom eq "no";
} elsif ($nxt =~ /^\/symbol\b/) {
$type = "CELL";
$type = "GRAPHIC" if $order == 0;
# mkdir $library unless -d $libraary;
# open(OUTPUT, ">$library/$symbol.asy") || die "$library/$symbol: $!";
open(OUTPUT, ">$symbol.asy") || die "$symbol: $!";
print OUTPUT "Version 4\n";
print OUTPUT "Symboltype $type\n";
print OUTPUT "$symdraw";
print OUTPUT "SYMATTR Value $symbol\n";
$prefix = "?";
$prefix = "D" if $library eq "diode";
$prefix = "R" if ($library eq "rcl") && ($symbol =~ /^R/);
$prefix = "R" if ($symbol =~ /^POT_US-/);
$prefix = "R" if ($symbol =~ /^TRIMPOT/);
$prefix = "C" if ($library eq "rcl") && ($symbol =~ /^C/);
$prefix = "C" if ($symbol =~ /^CPOL-/);
$prefix = "C" if ($library =~ /^CRYSTAL/i);
$prefix = "C" if ($symbol =~ /^CRYSTAL/);
$prefix = "L" if ($symbol =~ /^L-US/);
$prefix = "Q" if $library =~ /^transistor/;
$prefix = "-" if $library =~ /^supply/;
$prefix = "-" if $library =~ /^frame/;
$prefix = "-" if $symbol =~ /^device/i;
$prefix = "R" if $symbol =~ /^EDGE-/;
$prefix{$symbol} = $prefix;
print OUTPUT "SYMATTR Prefix $prefix\n";
print OUTPUT "SYMATTR Description $library/$symbol\n";
print OUTPUT "$sympins\n";
return;
} else {
die "Unrecognized: $nxt";
}
}
}
#
sub symbols {
while (&nxt) {
if ($nxt =~ /^symbol\b/) {
&symbol();
} elsif ($nxt =~ /^\/symbols\b/) {
return;
} else {
die "Unrecognized: $nxt";
}
}
}
#
#
sub gate {
die "gate name: $nxt" unless $nxt =~ /\bname="([^"]*)"/;
$gate = $1;
die "gate symbol: $nxt" unless $nxt =~ /\bsymbol="([^"]*)"/;
$symbol = $1;
die "x: $nxt" unless $nxt =~ /\bx="([^"]*)"/;
$x = &grid_units($1);
die "y: $nxt" unless $nxt =~ /\by="([^"]*)"/;
$y = -&grid_units($1);
$addlevel = "next";
$addlevel = $1 if $nxt =~ /\baddlevel="([^"]*)"/;
$swaplevel = "0";
$swaplevel = $1 if $nxt =~ /\bswaplevel="([^"]*)"/;
return;
}
#
sub gates {
while (&nxt) {
if ($nxt =~ /^gate\b/) {
&gate();
# Remember the symbol and it's offset for each in the device.
$gates{"$library;$deviceset;$gate"} = "$symbol;$x;$y";
} elsif ($nxt =~ /^\/gates\b/) {
return;
} else {
die "Unrecognized: $nxt";
}
}
}
#
sub connect {
return;
}
#
sub connects {
while (&nxt) {
if ($nxt =~ /^connect\b/) {
&connect();
} elsif ($nxt =~ /^\/connects\b/) {
return;
} else {
die "Unrecognized: $nxt";
}
}
}
#
sub attribute {
return;
}
#
sub attributes {
while (&nxt) {
if ($nxt =~ /^attribute\b/) {
&attribute();
} elsif ($nxt =~ /^\/attributes\b/) {
return;
} elsif ($nxt =~ /^\/technology\b/) {
return;
} else {
die "Unrecognized: $nxt";
}
}
}
#
sub technology {
while (&nxt) {
if ($nxt =~ /^attribute\b/) {
&attribute();
} elsif ($nxt =~ /^technology\b/) {
return;
} elsif ($nxt =~ /^\/technology\b/) {
next;
} elsif ($nxt =~ /^\/technologies\b/) {
return;
} else {
die "Unrecognized: $nxt";
}
}
}
#
sub technologies {
&nxt;
while ($nxt =~ /^technology\b/) {
&technology();
}
if ($nxt =~ /^\/technologies\b/) {
return;
} else {
die "Unrecognized: $nxt";
}
}
#
sub device {
while (&nxt) {
if ($nxt =~ /^connects\b/) {
&connects();
} elsif ($nxt =~ /^technologies\b/) {
&technologies();
} elsif ($nxt =~ /^\/device\b/) {
return;
} else {
die "Unrecognized: $nxt";
}
}
}
#
sub devices {
while (&nxt) {
if ($nxt =~ /^device\b/) {
&device();
} elsif ($nxt =~ /^\/devices\b/) {
return;
} else {
die "Unrecognized: $nxt";
}
}
}
#
#
sub deviceset {
die "deviceset name: $nxt" unless $nxt =~ /\bname="([^"]*)"/;
$deviceset = $1;
$prefix="";
$prefix = $1 if $nxt =~ /\bprefix="([^"]*)"/;
$uservalue="no";
$uservalue = $1 if $nxt =~ /\buservalue="([^"]*)"/;
while (&nxt) {
if ($nxt =~ /^description\b/) {
&description();
} elsif ($nxt =~ /^gates\b/) {
&gates();
} elsif ($nxt =~ /^devices\b/) {
&devices();
} elsif ($nxt =~ /^\/deviceset\b/) {
return;
} else {
die "Unrecognized: $nxt";
}
}
}
#
sub devicesets {
while (&nxt) {
if ($nxt =~ /^deviceset\b/) {
&deviceset();
} elsif ($nxt =~ /^\/devicesets\b/) {
return;
} else {
die "Unrecognized: $nxt";
}
}
}
#
#
#
sub library {
die "library name: $nxt" unless $nxt =~ /\bname="([^"]*)"/;
$library = $1;
while (&nxt) {
if ($nxt =~ /^description\b/) {
&description();
} elsif ($nxt =~ /^packages\b/) {
&packages();
} elsif ($nxt =~ /^symbols\b/) {
&symbols();
} elsif ($nxt =~ /^devicesets\b/) {
&devicesets();
} elsif ($nxt =~ /^\/library\b/) {
return;
} else {
die "Unrecognized: $nxt";
}
}
}
#
sub libraries {
%pinx = %piny = %prefix = ();
while (&nxt) {
if ($nxt =~ /^library\b/) {
&library();
} elsif ($nxt =~ /^\/libraries\b/) {
return;
} else {
die "Unrecognized: $nxt";
}
}
}
#
sub variantdef {
return;
}
#
sub variantdefs {
while (&nxt) {
if ($nxt =~ /^variantdef\b/) {
&variantdef();
} elsif ($nxt =~ /^\/variantdefs\b/) {
return;
} else {
die "Unrecognized: $nxt";
}
}
}
#
sub clearance {
return;
}
#
sub class {
while (&nxt) {
if ($nxt =~ /^clearance\b/) {
&clearance();
} elsif ($nxt =~ /^\/class\b/) {
return;
} else {
die "Unrecognized: $nxt";
}
}
}
#
sub classes {
while (&nxt) {
if ($nxt =~ /^class\b/) {
&class();
} elsif ($nxt =~ /^\/classes\b/) {
return;
} else {
die "Unrecognized: $nxt";
}
}
}
#
sub variant {
return;
}
#
#
sub part {
# attribute* and variant* are often empty,
# so directly follows .
die "part name: $nxt" unless $nxt =~ /\bname="([^"]*)"/;
$name = $1;
die "library: $nxt" unless $nxt =~ /\blibrary="([^"]*)"/;
$library = $1;
die "deviceset: $nxt" unless $nxt =~ /\bdeviceset="([^"]*)"/;
$deviceset = $1;
die "device: $nxt" unless $nxt =~ /\bdevice="([^"]*)"/;
$device = $1;
$technology = "";
$technology = $1 if $nxt =~ /\btechnology="([^"]*)"/;
$value = $deviceset;
$value = $1 if $nxt =~ /\bvalue="([^"]*)"/;
$value =~ s/\*/$device/ if $deviceset =~ /\*/;
while (&nxt) {
if ($nxt =~ /^attribute\b/) {
&attribute();
} elsif ($nxt =~ /^variant\b/) {
&variant();
} elsif ($nxt =~ /^part\b/) {
return;
} elsif ($nxt =~ /^\/parts\b/) {
return;
} elsif ($nxt =~ /^\/part\b/) {
return;
} else {
die "Unrecognized: $nxt";
}
}
}
#
sub parts {
while (&nxt) {
while ($nxt =~ /^part\b/) {
&part();
$discrete = 0;
$discrete = 1 if $library eq "rcl";
$deviceset{$name} = "$library;$deviceset";
$value{$name} = $value;
}
if ($nxt =~ /^\/parts\b/) {
return;
} else {
die "Unrecognized: $nxt";
}
}
}
#
sub plain {
$plain = "";
while (&nxt) {
if ($nxt =~ /^polygon\b/) {
&polygon();
die "unimplemented";
} elsif ($nxt =~ /^wire\b/) {
&wire();
$plain .= "LINE Normal $x1 $y1 $x2 $y2 $style\n";
#die "unimplemented";
} elsif ($nxt =~ /^text\b/) {
&text();
$plain .= "TEXT $x $y Left $size $txt\n";
} elsif ($nxt =~ /^dimension\b/) {
&dimension();
die "unimplemented";
} elsif ($nxt =~ /^circle\b/) {
&circle();
die "unimplemented";
} elsif ($nxt =~ /^rectangle\b/) {
&rectangle();
die "unimplemented";
} elsif ($nxt =~ /^frame\b/) {
&frame();
die "unimplemented";
} elsif ($nxt =~ /^hole\b/) {
&hole();
die "unimplemented";
} elsif ($nxt =~ /^\/plain\b/) {
return;
} else {
die "Unrecognized: $nxt";
}
}
}
sub spicerot {
local($rot) = @_;
return $rot unless $rot =~ /(M*R*)(\d+)/;
($rot, $angle) = ($1, $2);
$rot = "R" if $rot eq "";
$angle = 360 - $angle;
$angle %= 360;
return "$rot$angle";
}
#
#
#
sub instance {
# If attribute* is empty, directly follows .
die "part: $nxt" unless $nxt =~ /\bpart="([^"]*)"/;
$part = $1;
die "gate: $nxt" unless $nxt =~ /\bgate="([^"]*)"/;
$gate = $1;
die "x: $nxt" unless $nxt =~ /\bx="([^"]*)"/;
$x = &grid_units($1);
$x = &grid_snap($x);
die "y: $nxt" unless $nxt =~ /\by="([^"]*)"/;
$y = -&grid_units($1);
$y = &grid_snap($y);
$smashed = "no";
$smashed = $1 if $nxt =~ /\bsmashed="([^"]*)"/;
$rot = "r0";
$rot = $1 if $nxt =~ /\brot="([^"]*)"/;
while (&nxt) {
if ($nxt =~ /^attribute\b/) {
&attribute();
} elsif ($nxt =~ /^instance\b/) {
return;
} elsif ($nxt =~ /^\/instances\b/) {
return;
} elsif ($nxt =~ /^\/instance\b/) {
;
} else {
die "Unrecognized: $nxt";
}
}
}
#
sub instances {
while (&nxt) {
while ($nxt =~ /^instance\b/) {
&instance();
# Place an instance of the part at the specified coordinates.
# $deviceset{$part}/gate is sufficient to resolve the symbol.
$symbol = $gates{"$deviceset{$part};$gate"};
$symbol =~ s/;.*//;
if ($deviceset{$part} =~ /^supply/) {
# Convert supply pins into net names,
# thus connecting up the supplies.
$rot = &spicerot($rot);
$xoff = $pinx{$symbol};
$yoff = $piny{$symbol};
($xoff, $yoff) = (-$yoff, $xoff) if $rot =~ /R90$/i;
($xoff, $yoff) = (-$xoff, -$yoff) if $rot =~ /R180$/i;
($xoff, $yoff) = ($yoff, -$xoff) if $rot =~ /R270$/i;
$xoff = -$xoff if $rot =~ /^M/;
$x += $xoff;
$y += $yoff;
$sheet .= "FLAG $x $y $symbol\n";
} else {
# Place a symbol in the usual way.
$rot = &spicerot($rot);
$sheet .= "SYMBOL $symbol $x $y $rot\n";
$gate = "" if $gate eq 'G$1';
$sheet .= "SYMATTR InstName $part$gate\n";
$value = $value{$part};
$value = "1u" if $symbol =~ /^EDGE-/;
$value = $sheetno if $symbol eq "DOCFIELD";
$sheet .= "SYMATTR Value $value\n";
if ($symbol =~ /^EDGE-/) {
$offset = 16;
$mirror = 1;
$mirror = -$mirror if $rot =~ /^M/;
$x -= $mirror*$offset if $rot =~ /R0$/i;
$y -= $offset if $rot =~ /R90$/i;
$x += $mirror*$offset if $rot =~ /R180$/i;
$y += $offset if $rot =~ /R270$/i;
$sheet .= "FLAG $x $y $gate\n";
$sheet .= "IOPIN $x $y $gate BiDir\n";
}
}
}
if ($nxt =~ /^\/instances\b/) {
return;
} else {
die "Unrecognized: $nxt";
}
}
}
#
sub pinref {
return;
}
#
sub junction {
return;
}
#
#
#
#
sub label {
die "x: $nxt" unless $nxt =~ /\bx="([^"]*)"/;
$x = &grid_units($1);
$x = &grid_snap($x);
die "y: $nxt" unless $nxt =~ /\by="([^"]*)"/;
$y = -&grid_units($1);
$y = &grid_snap($y);
die "size: $nxt" unless $nxt =~ /\bsize="([^"]*)"/;
$size = $1;
die "layer: $nxt" unless $nxt =~ /\blayer="([^"]*)"/;
$layer = $1;
$font = "proportional";
$font = $1 if $nxt =~ /\bfont="([^"]*)"/;
$ratio = "8";
$ratio = $1 if $nxt =~ /\bratio="([^"]*)"/;
$rot = "R0";
$rot = $1 if $nxt =~ /\brot="([^"]*)"/;
$xref = "no";
$xref = $1 if $nxt =~ /\bxref="([^"]*)"/;
return;
}
#
sub segment {
while (&nxt) {
if ($nxt =~ /^pinref\b/) {
&pinref();
} elsif ($nxt =~ /^wire\b/) {
&wire();
$x1 = &grid_snap($x1);
$y1 = &grid_snap($y1);
$x2 = &grid_snap($x2);
$y2 = &grid_snap($y2);
$sheet .= "WIRE $x1 $y1 $x2 $y2\n";
} elsif ($nxt =~ /^junction\b/) {
&junction();
} elsif ($nxt =~ /^label\b/) {
&label();
$segments .= "FLAG $x $y $net\n";
} elsif ($nxt =~ /^\/segment\b/) {
return;
} else {
die "Unrecognized: $nxt";
}
}
}
#
sub bus {
while (&nxt) {
if ($nxt =~ /^segment\b/) {
&segment();
} elsif ($nxt =~ /^\/bus\b/) {
return;
} else {
die "Unrecognized: $nxt";
}
}
}
#
sub busses {
while (&nxt) {
if ($nxt =~ /^bus\b/) {
&bus();
} elsif ($nxt =~ /^\/busses\b/) {
return;
} else {
die "Unrecognized: $nxt";
}
}
}
#
#
sub net {
die "net name: $nxt" unless $nxt =~ /\bname="([^"]*)"/;
$net = $1;
$net =~ s/^(\d+)$/_\1/;
$net =~ s/=/_/g;
$class = "0";
$class = $1 if $nxt =~ /\bclass="([^"]*)"/;
$segments = "";
while (&nxt) {
if ($nxt =~ /^segment\b/) {
&segment();
} elsif ($nxt =~ /^\/net\b/) {
print OUTPUT $segments;
return;
} else {
die "Unrecognized: $nxt";
}
}
}
#
sub nets {
while (&nxt) {
if ($nxt =~ /^net\b/) {
&net();
} elsif ($nxt =~ /^\/nets\b/) {
return;
} else {
die "Unrecognized: $nxt";
}
}
}
#
sub sheet {
while (&nxt) {
if ($nxt =~ /^description\b/) {
&description();
} elsif ($nxt =~ /^plain\b/) {
$plain = "";
&plain();
print OUTPUT $plain;
print OUTPUT "TEXT 0 8 Left 2 .lib myparts.lib\n";
} elsif ($nxt =~ /^instances\b/) {
&instances();
} elsif ($nxt =~ /^busses\b/) {
&busses();
} elsif ($nxt =~ /^nets\b/) {
&nets();
} elsif ($nxt =~ /^\/sheet\b/) {
print OUTPUT $sheet;
return;
} else {
die "Unrecognized: $nxt";
}
}
}
#
sub sheets {
$sheetno = 1;
while (&nxt) {
if ($nxt =~ /^sheet\b/) {
$sheet = "SHEET $sheetno\n";
&sheet();
$sheetno++;
} elsif ($nxt =~ /^\/sheets\b/) {
return;
} else {
die "Unrecognized: $nxt";
}
}
}
#
sub approved {
return;
}
#
sub errors {
while (&nxt) {
if ($nxt =~ /^approved\b/) {
&approved();
} elsif ($nxt =~ /^\/errors\b/) {
return;
} else {
die "Unrecognized: $nxt";
}
}
}
#
sub plain {
#
# A plain consists of polygons, wires, texts, dimensions, circles,
# rectangles, frames, and holes.
while (&nxt) {
if ($nxt =~ /^description\b/) {
&description();
} elsif ($nxt =~ /^polgon\b/) {
&polgon();
} elsif ($nxt =~ /^wire\b/) {
&wire();
} elsif ($nxt =~ /^text\b/) {
&text();
# TODO: dimension
} elsif ($nxt =~ /^dimension\b/) {
&dimension();
} elsif ($nxt =~ /^circle\b/) {
&circle();
} elsif ($nxt =~ /^rectangle\b/) {
&rectangle();
} elsif ($nxt =~ /^frame\b/) {
&frame();
} elsif ($nxt =~ /^hole\b/) {
&hole();
} elsif ($nxt =~ /^\/plain\b/) {
return;
} else {
die "Unrecognized: $nxt";
}
}
}
#
sub board {
die "Not a board" unless $nxt =~ /^board\b/;
#
# A board consists of description, plain, libraries, attributes, variantdefs,
# classes, designrules, autorouter, elements, signals, and errors.
while (&nxt) {
if ($nxt =~ /^description\b/) {
&description();
} elsif ($nxt =~ /^plain\b/) {
&plain();
} elsif ($nxt =~ /^libraries\b/) {
&libraries();
} elsif ($nxt =~ /^attributes\b/) {
&attributes();
} elsif ($nxt =~ /^variantdefs\b/) {
&variantdefs();
} elsif ($nxt =~ /^classes\b/) {
&classes();
} elsif ($nxt =~ /^designrules\b/) {
&designrules();
} elsif ($nxt =~ /^autorouter\b/) {
&autorouter();
} elsif ($nxt =~ /^elements\b/) {
open(OUTPUT, ">$f") || die "$f: $!";
&elements();
} elsif ($nxt =~ /^signals\b/) {
&ignals();
} elsif ($nxt =~ /^errors\b/) {
&errors();
} elsif ($nxt =~ /^\/board\b/) {
return;
} else {
die "Unrecognized: $nxt";
}
}
}
sub schematic {
die "Not a schematic" unless $nxt =~ /^schematic\b/;
%deviceset = %value = %gates = ();
#
# A schematic consists of description, libraries, attributes, variantdefs,
# classes, parts, sheets, and errors.
while (&nxt) {
if ($nxt =~ /^description\b/) {
&description();
} elsif ($nxt =~ /^libraries\b/) {
&libraries();
} elsif ($nxt =~ /^attributes\b/) {
&attributes();
} elsif ($nxt =~ /^variantdefs\b/) {
&variantdefs();
} elsif ($nxt =~ /^classes\b/) {
&classes();
} elsif ($nxt =~ /^parts\b/) {
open(OUTPUT, ">$f") || die "$f: $!";
&parts();
} elsif ($nxt =~ /^sheets\b/) {
&sheets();
} elsif ($nxt =~ /^errors\b/) {
&errors();
} elsif ($nxt =~ /^\/schematic\b/) {
return;
} else {
die "Unrecognized: $nxt";
}
}
}
#
sub note {
return;
}
#
#
sub setting {
return;
}
#
sub settings {
while (&nxt) {
if ($nxt =~ /^setting\b/) {
&setting();
} elsif ($nxt =~ /^\/settings\b/) {
return;
} else {
die "Unrecognized: $nxt";
}
}
}
#
#
sub grid {
die "distance: $nxt" unless $nxt =~ /\bdistance="([^"]*)"/;
$grid_distance = $1;
die "unitdist: $nxt" unless $nxt =~ /\bunitdist="([^"]*)"/;
die "should be inches, not $unitdist" unless $1 eq "inch";
$grid_distance *= 25.4; # convert from mm
$grid_distance /= 160; # 160 dpi
return;
}
#
sub layer {
return;
}
#
sub layers {
while (&nxt) {
if ($nxt =~ /^layer\b/) {
&layer();
} elsif ($nxt =~ /^\/layers\b/) {
return;
} else {
die "Unrecognized: $nxt";
}
}
}
#
sub drawing {
#
# A schematic consists of description, libraries, attributes, variantdefs,
# classes, parts, sheets, and errors.
while (&nxt) {
if ($nxt =~ /^settings\b/) {
&settings();
} elsif ($nxt =~ /^grid\b/) {
&grid();
} elsif ($nxt =~ /^layers\b/) {
&layers();
} elsif ($nxt =~ /^board\b/) {
&board();
} elsif ($nxt =~ /^(library|schematic)\b/) {
&schematic();
} elsif ($nxt =~ /^\/drawing\b/) {
return;
} else {
die "Unrecognized: $nxt";
}
}
}
#
sub eagle {
# An eagle drawing is basically an XML header, and a
&nxt;
while ($nxt !~ /^drawing\b/) {
&nxt;
}
&drawing();
}
foreach $f (@ARGV) {
open(INPUT, $f) || die "$f: $!";
warn "Processing $f\n";
$f =~ s/[.]sch/.asc/ || die "$f: bad extension";
$f =~ s/.*\///;
&eagle;
}
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#
#