我正在编写一个.NET API (C#)来管理KiCAD PCB文件。根据docs (这里),它们的格式是一种S-表达式.我尝试重用一些S表达式解析器,但由于几个原因它们不能满足我的需要,所以我决定编写一个,但我发现自己陷入了困境。作为第一次尝试,我写下了一个简单的函数,该函数递归地下降到文件结构中,并创建一个与结构匹配的System.Windows.Forms.TreeNode层次结构(我使用TreeNode,因为我使用TreeView组件来描述所解析的结构):
private TreeNode Parser(StreamReader srStream, TreeNode tnCurrentNode)
{
bool _string = false;
do
{
TreeNode _tnNode = null;
char _c;
_c = (char)srStream.Read();
if (_string)
{
tnCurrentNode.Text += _c;
if (_c == '"')
_string = false;
}
else
switch (_c)
{
case '(':
_tnNode = new TreeNode();
tnCurrentNode.Nodes.Add(Parser(srStream, _tnNode));
break;
case ')':
return tnCurrentNode;
case '\n':
case '\r':
break;
case '"':
tnCurrentNode.Text += _c;
_string = true;
break;
default:
tnCurrentNode.Text += _c;
break;
}
} while (!srStream.EndOfStream);
return tnCurrentNode;
}在那之后,我写下了一个序列化程序来写回文件。一切都很好,但是有一种情况由我的解析器处理不当,而且我一直无法找到适当的解决方案:
(fp_text value V23105 (at -2 0 180) (layer F.SilkS) hide
(effects (font (size 1 1) (thickness 0.25)))
)隐藏令牌位置未被正确管理(不能在原始位置中序列化)。原因很简单:虽然解析器正确地处理子节点,因为它们以开头括号开始,但它只是忽略位于相同级别(即由空格分隔的值)的值,例如隐藏选项。我该如何处理这种情况呢?我尝试了几种方法,但我只是进入了一些堆栈溢出异常(我刚刚失去了递归的控制)。
同时,我定义了一个自定义类来处理节点(用于代替TreeNode):
public class KiCADNode
{
public string Value { get; set; }
public NodeType Type { get; set; }
private readonly List<KiCADNode> _Nodes = new List<KiCADNode>();
public ICollection<KiCADNode> Nodes { get { return _Nodes; } }
public static implicit operator TreeNode(KiCADNode node)
{
if (node == null)
return null;
TreeNode _treenode = new TreeNode();
_treenode.Text = node.ToString();
foreach (KiCADNode _node in node._Nodes)
_treenode.Nodes.Add((TreeNode)_node);
return _treenode;
}
public override string ToString()
{
StringBuilder _sb = new StringBuilder();
if (Type == NodeType.List)
_sb.Append('(');
_sb.Append(Value);
if (Type == NodeType.Atom)
_sb.Append(' ');
if (Type == NodeType.List)
_sb.Append(')');
return _sb.ToString();
}
public KiCADNode()
{
Type = NodeType.Atom;
}
public KiCADNode(NodeType type)
{
Type = type;
}
public KiCADNode(string value) : this()
{
Value = value;
}
public KiCADNode(string value, NodeType type) : this(value)
{
Type = type;
}
private static KiCADNode Parse(StreamReader input)
{
KiCADNode _node = new KiCADNode("PCB");
return Parser(input, _node);
}
private static KiCADNode Parser(StreamReader input, KiCADNode current_node)
{
bool _string = false;
while (!input.EndOfStream)
{
KiCADNode _new_node = null;
char _c;
_c = (char)input.Read();
if (_string)
{
current_node.Value += _c;
if (_c == '"')
_string = false;
}
else
switch (_c)
{
case '(':
_new_node = new KiCADNode(NodeType.List);
current_node.Nodes.Add(Parser(input, _new_node));
break;
case ')':
return current_node;
case '\n':
case '\r':
break;
case '"':
current_node.Value += _c;
_string = true;
break;
default:
current_node.Value += _c;
break;
}
}
return current_node;
}
public static KiCADNode Parse(string filename)
{
if (!File.Exists(filename))
return null;
using (StreamReader _input = new StreamReader(filename))
{
return Parse(_input);
}
}
}发布于 2017-03-03 16:59:04
https://stackoverflow.com/questions/42346548
复制相似问题