예제 #1
0
 private void ParseLines(SimpleCircuitLexer lexer, Circuit ckt)
 {
     do
     {
         ParseLine(lexer, ckt);
         if (!lexer.Is(TokenType.Newline) && !lexer.Is(TokenType.EndOfContent))
         {
             throw new ParseException($"Expected a new line", lexer.Line, lexer.Position);
         }
         while (lexer.Is(TokenType.Newline))
         {
             lexer.Next();
         }
     }while (!lexer.Is(TokenType.EndOfContent));
 }
예제 #2
0
        private List <WireDescription> ParseWire(SimpleCircuitLexer lexer)
        {
            var wires = new List <WireDescription>();

            lexer.Check(TokenType.OpenBracket, "<");
            do
            {
                var direction = ParseDirection(lexer);
                wires.Add(new WireDescription
                {
                    Direction = direction,
                    Length    = -1.0
                });
                if (lexer.Is(TokenType.Number))
                {
                    wires[wires.Count - 1].Length = double.Parse(lexer.Content, System.Globalization.CultureInfo.InvariantCulture);
                    lexer.Next();
                }
            }while (!lexer.Is(TokenType.CloseBracket, ">"));
            lexer.Next();
            return(wires);
        }
예제 #3
0
 private string ParseDirection(SimpleCircuitLexer lexer)
 {
     if (lexer.Is(TokenType.Word))
     {
         switch (lexer.Content)
         {
         case "u":
         case "d":
         case "l":
         case "r":
             var dir = lexer.Content;
             lexer.Next();
             return(dir);
         }
     }
     if (lexer.Is(TokenType.Question))
     {
         lexer.Next();
         return("?");
     }
     throw new ParseException($"Expected a direction", lexer.Line, lexer.Position);
 }
예제 #4
0
 private void ParseLine(SimpleCircuitLexer lexer, Circuit ckt)
 {
     if (lexer.Is(TokenType.Newline))
     {
         return;
     }
     else if (lexer.Is(TokenType.Dash))
     {
         ParseEquation(lexer, ckt);
     }
     else if (lexer.Is(TokenType.Dot))
     {
         ParseOption(lexer, ckt);
     }
     else if (lexer.Is(TokenType.Word))
     {
         ParseChain(lexer, ckt);
     }
     else
     {
         throw new ParseException($"Could not read {lexer.Content}", lexer.Line, lexer.Position);
     }
 }
예제 #5
0
        private IComponent ParseComponentLabel(SimpleCircuitLexer lexer, Circuit ckt)
        {
            var component = GetComponent(ParseName(lexer), ckt);

            if (lexer.Is(TokenType.OpenBracket, "("))
            {
                lexer.Next();
                var label = ParseLabel(lexer);
                if (component is ILabeled lbl)
                {
                    lbl.Label = label;
                }
                lexer.Check(TokenType.CloseBracket, ")");
            }
            return(component);
        }
예제 #6
0
        private PinDescription ParsePin(SimpleCircuitLexer lexer, Circuit ckt)
        {
            var result = new PinDescription();

            result.ComponentName = lexer.Content;
            result.Component     = ParseComponentLabel(lexer, ckt);
            if (lexer.Is(TokenType.OpenBracket, "["))
            {
                lexer.Next();
                var pin = ParseName(lexer);
                lexer.Check(TokenType.CloseBracket, "]");
                result.AfterName = pin;
                result.After     = (TranslatingPin)result.Component.Pins[pin];
            }
            return(result);
        }
예제 #7
0
        private void ParseEquation(SimpleCircuitLexer lexer, Circuit ckt)
        {
            if (!lexer.Is(TokenType.Dash))
            {
                throw new ParseException($"A dash was expected", lexer.Line, lexer.Position);
            }
            lexer.Next();

            // Add the first equation
            var a = ParseSum(lexer, ckt);

            lexer.Check(TokenType.Equals);
            var b = ParseSum(lexer, ckt);

            if (a is Function fa && b is Function fb)
            {
                ckt.Add(fa - fb, $"keep {fa} and {fb} equal");
            }
예제 #8
0
        private PinDescription ParseDoublePin(SimpleCircuitLexer lexer, Circuit ckt)
        {
            string beforePin = null;

            if (lexer.Is(TokenType.OpenBracket, "["))
            {
                lexer.Next();
                beforePin = ParseName(lexer);
                lexer.Check(TokenType.CloseBracket, "]");
            }
            var result = ParsePin(lexer, ckt);

            if (beforePin != null)
            {
                result.BeforeName = beforePin;
                result.Before     = (TranslatingPin)result.Component.Pins[beforePin];
            }
            return(result);
        }
예제 #9
0
        private void ParseChain(SimpleCircuitLexer lexer, Circuit ckt)
        {
            var            start = ParsePin(lexer, ckt);
            PinDescription end   = null;

            while (lexer.Is(TokenType.OpenBracket))
            {
                if (start.Component is Point pts)
                {
                    pts.Wires++;
                }
                var wires = ParseWire(lexer);
                end = ParseDoublePin(lexer, ckt);

                // String them together
                var lastPin = start.After ?? (TranslatingPin)start.Component.Pins.Last(p => p is TranslatingPin);
                var wire    = new Wire(lastPin);
                ckt.Add(wire);
                for (var i = 0; i < wires.Count; i++)
                {
                    TranslatingPin nextPin;
                    if (i < wires.Count - 1)
                    {
                        var pt = new Point("X:" + (_anonIndex++));
                        ckt.Add(pt);
                        nextPin   = (TranslatingPin)pt.Pins.First(p => p is TranslatingPin);
                        pt.Wires += 2;
                    }
                    else
                    {
                        nextPin = end.Before ?? (TranslatingPin)end.Component.Pins.First(p => p is TranslatingPin);
                        if (end.Component is Point pte)
                        {
                            pte.Wires++;
                        }
                    }

                    // Create a new segment for our wire
                    var length = new Unknown($"W{++_wireIndex}.Length", UnknownTypes.Length);
                    wire.To(nextPin, length);
                    var dir = wires[i].Direction.ToLower();

                    // Constrain the positions
                    switch (dir)
                    {
                    case "u": ckt.Add(nextPin.X - lastPin.X, $"align {nextPin} with {lastPin} (line {lexer.Line})"); ckt.Add(lastPin.Y - nextPin.Y - length, $"define wire {length} (line {lexer.Line})"); break;

                    case "d": ckt.Add(nextPin.X - lastPin.X, $"align {nextPin} with {lastPin} (line {lexer.Line})"); ckt.Add(nextPin.Y - lastPin.Y - length, $"define wire {length} (line {lexer.Line})"); break;

                    case "l": ckt.Add(lastPin.X - nextPin.X - length, $"define wire {length} (line {lexer.Line})"); ckt.Add(lastPin.Y - nextPin.Y, $"align {nextPin} and {lastPin} (line {lexer.Line})"); break;

                    case "r": ckt.Add(nextPin.X - lastPin.X - length, $"define wire {length} (line {lexer.Line})"); ckt.Add(lastPin.Y - nextPin.Y, $"align {nextPin} and {lastPin} (line {lexer.Line})"); break;
                    }

                    // Constrain the directions
                    if (lastPin is IRotating rlastPin)
                    {
                        switch (dir)
                        {
                        case "u": ckt.Add(rlastPin.NormalY + 1, $"point {rlastPin} up (line {lexer.Line})"); ckt.Add(rlastPin.NormalX, $"point {rlastPin} up (line {lexer.Line})"); break;

                        case "d": ckt.Add(rlastPin.NormalY - 1, $"point {rlastPin} down (line {lexer.Line})"); ckt.Add(rlastPin.NormalX, $"point {rlastPin} down (line {lexer.Line})"); break;

                        case "l": ckt.Add(rlastPin.NormalY, $"point {rlastPin} left (line {lexer.Line})"); ckt.Add(rlastPin.NormalX + 1, $"point {rlastPin} left (line {lexer.Line})"); break;

                        case "r": ckt.Add(rlastPin.NormalY, $"point {rlastPin} right (line {lexer.Line})"); ckt.Add(rlastPin.NormalX - 1, $"point {rlastPin} right (line {lexer.Line})"); break;

                        case "?":
                            ckt.Add(lastPin.X + rlastPin.NormalX * length - nextPin.X, $"point {rlastPin} to {nextPin} (line {lexer.Line})");
                            ckt.Add(lastPin.Y + rlastPin.NormalY * length - nextPin.Y, $"point {rlastPin} to {nextPin} (line {lexer.Line})");
                            break;
                        }
                    }
                    if (nextPin is IRotating rnextPin)
                    {
                        switch (dir)
                        {
                        case "u": ckt.Add(rnextPin.NormalY - 1, $"point {rnextPin} up (line {lexer.Line})"); ckt.Add(rnextPin.NormalX, $"point {rnextPin} up (line {lexer.Line})"); break;

                        case "d": ckt.Add(rnextPin.NormalY + 1, $"point {rnextPin} down (line {lexer.Line})"); ckt.Add(rnextPin.NormalX, $"point {rnextPin} down (line {lexer.Line})"); break;

                        case "l": ckt.Add(rnextPin.NormalY, $"point {rnextPin} left (line {lexer.Line})"); ckt.Add(rnextPin.NormalX - 1, $"point {rnextPin} left (line {lexer.Line})"); break;

                        case "r": ckt.Add(rnextPin.NormalY, $"point {rnextPin} right (line {lexer.Line})"); ckt.Add(rnextPin.NormalX + 1, $"point {rnextPin} right (line {lexer.Line})"); break;

                        case "?":
                            ckt.Add(nextPin.X + rnextPin.NormalX * length - lastPin.X, $"point {rnextPin} to {lastPin} (line {lexer.Line})");
                            ckt.Add(nextPin.Y + rnextPin.NormalY * length - lastPin.Y, $"point {rnextPin} to {lastPin} (line {lexer.Line})");
                            break;
                        }
                    }

                    // Fix the wire length if necessary
                    if (wires[i].Length >= 0)
                    {
                        ckt.Add(length - wires[i].Length, $"fix wire length {length} to {wires[i].Length} (line {lexer.Line})");
                    }

                    lastPin = nextPin;
                }
                start = end;
            }

            if (end != null && end.AfterName != null)
            {
                if (end.BeforeName == null)
                {
                    Warn(this, new WarningEventArgs($"Pin {end.AfterName} was specified at the end of line {lexer.Line}, but it isn't used. Did you mean \"[{end.AfterName}]{end.ComponentName}\" instead of \"{end.ComponentName}[{end.AfterName}]\"?"));
                }
                else
                {
                    Warn(this, new WarningEventArgs($"Pin {end.AfterName} was specified at the end of line {lexer.Line}, but it isn't used."));
                }
            }
        }