r5802 - in trunk/gta02-core/bom: . test/3
werner at docs.openmoko.org
werner at docs.openmoko.org
Fri Jan 29 10:26:11 CET 2010
Author: werner
Date: 2010-01-29 10:26:10 +0100 (Fri, 29 Jan 2010)
New Revision: 5802
Modified:
trunk/gta02-core/bom/README
trunk/gta02-core/bom/parser.pl
trunk/gta02-core/bom/test/3/print.pl
Log:
More work on the substitution mechanism. Almost done.
Modified: trunk/gta02-core/bom/README
===================================================================
--- trunk/gta02-core/bom/README 2010-01-28 19:36:30 UTC (rev 5801)
+++ trunk/gta02-core/bom/README 2010-01-29 09:26:10 UTC (rev 5802)
@@ -31,20 +31,91 @@
A substitutions file specifies rules for translating component
parameters in schematics to part characteristics.
-matches -> actions !
+A substitution rule consists of one or more conditions and zero or
+more assignments. The conditions are of the form field=pattern. The
+field can be a per-component fields KiCad provides or any parameter
+set by substitutions.
-matches -> actions {
+KiCad fields are named as follows:
+
+KiCad field Field name
+----------- ----------
+Reference REF (*)
+Value VAL
+FP Footprint
+Field1 F1
+... ...
+
+(*) As a shortcut, REF= can be omitted.
+
+Note that fields with a user-defined name currently still only appear
+as F1, F2, etc.
+
+Field names are case-insensitive.
+
+The pattern is uses a notation similar to filename globbing. There
+are the following special constructs:
+
+- * matches a string of any length
+- ? matches a single character
+- (...) matches the pattern between the parentheses and records the
+ string matched
+- $X marks a value in nXn notation, e.g., 4u7 or 100R. Such values
+ are converted to SI-like notation.
+
+A rule is applied when all conditions are fulfilled. In this case,
+assignments of the form field=value are executed. Strings obtained
+in the match can be included in a value as follows:
+
+- $field and ${field} are replaced by the respective field
+- $field:n and ${field:n} are replaced by the n-th (...) pattern in
+ the match of the respective field
+
+If a rule ends with an exclamation mark, the substitution process stops
+after the rule is applied. Otherwise, further rules are processed.
+
+Examples:
+
+R* val=$R -> R=$val
+
+This rule translates the values of all resistors to SI notation.
+
+D* F1=(*)Vdc -> T=TSV Vdc=F1:1
+
+This rule sets the parameters T and Vdc for Zeners acting as TSVs.
+
+If a set of rules has a common set of conditions or assignments, the
+more compact block notation can be used instead of repeating them for
+each rule:
+
+common-conditions -> common-assignments {
+ rule-specific-conditions -> rule-specific-assignments
...
}
-(...) -> $n or ${n}
-$u -> canonicalize unit
-REF
-FP
-F1
-...
+Rules in a block only match if both the common and the rule-specific
+conditions are met. Then the common and the rule-specific assignments
+are performed. If a condition or an assignment appears both in the
+common and the rule-specific part, only the latter is used.
+Long lines can be wrapped by indenting the continuation lines. Note
+that { and ! are also considered to be part of the same line as the
+rest of the rule. In particular, the following construct wouldn't
+work:
+X=Y
+{
+ ...
+}
+
+However, this would:
+
+X=Y
+ {
+ ...
+}
+
+
Parts list (.par)
------------------
Modified: trunk/gta02-core/bom/parser.pl
===================================================================
--- trunk/gta02-core/bom/parser.pl 2010-01-28 19:36:30 UTC (rev 5801)
+++ trunk/gta02-core/bom/parser.pl 2010-01-29 09:26:10 UTC (rev 5802)
@@ -1,5 +1,8 @@
#!/usr/bin/perl
+use re 'eval';
+
+
sub skip
{
# do nothing
@@ -146,12 +149,162 @@
# $last
# $last_action
#
-# to do:
-# - unit canonicalization
-# - glob to RE rewriting for pattern
-# - $n expansion for value
+
#
+# $cvn_from{internal-handle} = index
+# $cvn_to{internal-handle} = index
+# $cvn_unit{internal-handle} = unit-name
+# $cvn_num = internal-handle
+# $found{field-or-subfield} = string
+
+#
+# We convert each input pattern into two regular expressions: the first matches
+# units in the nXn notation, e.g., 4u7 or 100R. The second matches them in SI
+# notation (sans space).
+#
+# When matching (sub_match), we first apply the first expression. Each time we
+# encounter a unit ($R, $F, etc.), __cvn is called. __cvn stores the index of
+# the unit in %cvn_from and %cvn_to.
+#
+# We then pick these substrings from the input string and convert the units to
+# SI notation. At the same time, we normalize the mantissa. Once done, we run
+# the second expression. This one always matches (hopefully :-)
+#
+# All (...) ranges in the original pattern have been replaced with named
+# capture buffers in the second expression, so all these subfields are now
+# gathered in the $+ array. (The same also happened in the first pass, but we
+# ignore it.)
+#
+# Finally, when expanding a value (sub_expand), we look for $field and
+# $field:index, and expand accordingly.
+#
+
+
+sub __cvn
+{
+ local ($num) = @_;
+
+ $cvn_from{$num} = $-[$#-];
+ $cvn_to{$num} = $+[$#+];
+}
+
+
+sub sub_pattern
+{
+ local ($field, $p) = @_;
+ my $n = 0;
+ $p =~ s/\./\./g;
+ $p =~ s/\+/\\+/g;
+ $p =~ s/\?/./g;
+ $p =~ s/\*/.*/g;
+ my $tmp = "";
+ while ($p =~ /^([^\(]*)\(/) {
+ $n++;
+ $tmp .= "$1(?'${field}__$n'";
+ $p = $';
+ }
+ $p = $tmp.$p;
+ my $q = $p;
+ while ($p =~ /^([^\$]*)\$(.)/) {
+ $p = "$1(\\d+$2\\d*|\\d+[GMkmunpf$2]\\d*)(?{ &__cvn($cvn_num); })$'";
+ $cvn_unit{$cvn_num} = $2;
+ die unless $q =~ /^([^\$]*)\$(.)/;
+ $q = "$1(\\d+(\.\\d+)[GMkmunpf]?$2)$'";
+ $cvn_num++;
+ }
+ return ($p, $q);
+}
+
+
+sub sub_value
+{
+ return $_[0];
+}
+
+
+sub sub_match
+{
+ local ($s, $field, $m1, $m2) = @_;
+
+ #
+ # Perform the first match and record where we saw $<unit> patterns.
+ #
+ undef %cvn_from;
+ undef %cvn_to;
+ return undef unless $s =~ $m1;
+
+ #
+ # Convert the unit patterns to almost-SI notation. (We don't put a space
+ # after the number, but the rest is SI-compliant.)
+ #
+ my $off = 0;
+ for (keys %cvn_from) {
+ my $unit = $cvn_unit{$_};
+ my $from = $cvn_from{$_}+$off;
+ my $len = $cvn_to{$_}-$cvn_from{$_};
+ die unless substr($s, $from, $len) =~
+ /(\d+)$unit(\d*)|(\d+)([GMkmunpf])(\d*)/;
+
+ #
+ # Normalize to \d+.\d*
+ #
+ my $v = "$1$3.$2$5";
+ my $exp = $4 eq "" ? " " : $4;
+
+ #
+ # Mantissa must be < 1000.
+ # Do the math as string operation to avoid rounding errors.
+ #
+ while ($v =~ /(\d+)(\d{3})\./) {
+ $v = "$1.$2$'";
+ $exp =~ tr/GMk munpf/TGMk munp/;
+ }
+
+ #
+ # Mantissa must be >= 1.
+ #
+ while ($v =~ /\b0\.(\d+)/) {
+ if (length $1 < 3) {
+ $v = $1.("0" x (3-length $1)).".";
+ } else {
+ $v = substr($1, 0, 3).".".substr($1, 3);
+ }
+ $exp =~ tr/GMk munpf/Mk munpa/;
+ }
+ $exp =~ s/ //;
+ $v =~ s/\.$//;
+ $v = $v.$exp.$unit;
+ $off += length($v)-$len;
+ substr($s, $from, $len, $v);
+ }
+
+ #
+ # Run the second match on the string to process any (...) patterns
+ #
+ $found{$field} = $s;
+ die $m2 unless $s =~ $m2;
+ for (keys %+) {
+ $found{$_} = $+{$_};
+ }
+ return $s;
+}
+
+
+sub sub_expand
+{
+ local ($s) = @_;
+
+ while ($s =~ /^([^\$]*)\$([[:alpha:]]\w*)(:(\d+))?|^([^\$]*)\${([[:alpha:]]\w*)(:(\d+))?}/) {
+ my $name = "$2$5";
+ $name .= "__$4$7" if defined($4) || defined($7);
+ die "don't know \"$name\"" unless defined $found{$name};
+ $s = $1.$found{$name}.$';
+ }
+ return $s;
+}
+
+
sub sub
{
/^(\s*)/;
@@ -184,9 +337,9 @@
$f = shift @f;
last if $f eq "->" || $f eq "{" || $f eq "}" || $f eq "!";
if ($f =~ /=/) {
- $match_stack[0]{uc($`)} = $';
+ $match_stack[0]{uc($`)} = [ &sub_pattern(uc($`), $') ];
} else {
- $match_stack[0]{"REF"} = $f;
+ $match_stack[0]{"REF"} = [ &sub_pattern("REF", $f) ];
}
}
$last_action = 1 if $f eq "->";
@@ -196,7 +349,7 @@
$f = shift @f;
last if $f eq "{" || $f eq "!";
die unless $f =~ /=/;
- $action_stack[0]{uc($`)} = $';
+ $action_stack[0]{uc($`)} = &sub_value($');
}
}
$may_cont = 0;
@@ -215,12 +368,12 @@
my $n = $#end;
push(@match, undef);
push(@action, undef);
- for my $m (@match_stack) {
+ for my $m (reverse @match_stack) {
for (keys %{ $m }) {
$match[$n]{$_} = $m->{$_};
}
}
- for my $a (@action_stack) {
+ for my $a (reverse @action_stack) {
for (keys %{ $a }) {
$action[$n]{$_} = $a->{$_};
}
Modified: trunk/gta02-core/bom/test/3/print.pl
===================================================================
--- trunk/gta02-core/bom/test/3/print.pl 2010-01-28 19:36:30 UTC (rev 5801)
+++ trunk/gta02-core/bom/test/3/print.pl 2010-01-29 09:26:10 UTC (rev 5802)
@@ -9,7 +9,8 @@
}
for ($i = 0; $i != @end; $i++) {
for (sort keys %{ $match[$i] }) {
- print "$_=$match[$i]{$_} ";
+ @m = @{ $match[$i]{$_} };
+ print "$_=$m[0]/$m[1] ";
}
print "->";
for (sort keys %{ $action[$i] }) {
More information about the commitlog
mailing list