Grid Based Digital Logic (Duodyadic Tiles) Duodyadic tiles are kinds of square function blocks that take two inputs, one from their top side and one from their left side, and have two outputs, one on their right side and one on their bottom side. Each of their outputs is a separate function of both of their inputs.
For example, if # represents a generic tile, the right output R is a function f of inputs T and L, and the bottom output B is another function g of T and L:
 T
L#R         R = f(T, L)
 B          B = g(T, L)

(The tiles are termed &quot;duo&quot; since there are two functions, and &quot;dyadic&quot; since both functions have two arguments.)
Tiles can then be composed together on a grid, the outputs of one tile going directly into the inputs of the tiles it neighbors. Here for example, the right output of the left # goes into the left input of the right #:
 AB         D = f(f(A, C), B)
C##D        E = g(A, C)
 EF         F = g(f(A, C), B)

You can imagine that given a set of duodyadic tiles, each with specific functionality, complex (and potentially useful) compositions could be made.
In this challenge, we'll only be concerned with the traditional set of ten logic based duodyadic tiles, where all the inputs and outputs are single-bit binary numbers (zeros or ones). We'll use a separate ASCII character to denote each type of tile.
The tile characters and their input-output relations are as follows:
(T is for top input, L for left input, R for right output, B for bottom output.)

Zero: 0 or   (space) → R = 0, B = 0
One: 1 → R = 1, B = 1
Cross: + → R = L, B = T
Mirror: \ → R = T, B = L
Top only: U → R = T, B = T
Left only: ) → R = L, B = L
Not: ! → R = not L, B = not T
And: &amp; → R = L and T, B = L and T
Or: | → R = L or T, B = L or T
Xor: ^ → R = L xor T, B = L xor T

Challenge
Write a program or function that takes in a rectangular grid of the characters 0 1+\U)!&amp;|^ that represents a &quot;circuit&quot; made using the ten logic based duodyadic tiles. You also need to take in two strings of 0's and 1's; one will be the left input column and one will be the top input row. Your program/function needs to print/return the bottom output row and the right output column (also in 0's and 1's).
For example, in this grid
+++
+++

all the inputs flow straight across the grid to the outputs
 ABC
D+++D
E+++E
 ABC

so an input of 010/01 would have output 010/01:
 010
0+++0
1+++1
 010

The exact output of your program would be [bottom output row]\n[right output column] or [bottom output row]/[right output column]:
010
01

or
010/01

If you wrote a function, you could return the two strings in a tuple or list (or still print them).
Details

Take the three inputs as strings in any reasonable manner (preferably in the order grid, top row, left column): command line, text file, sdtin, function arg.
You can assume the input row and column lengths will match the grid dimensions and will only contain 0's and 1's.
Your grid must use the proper characters (0 1+\U)!&amp;|^). Remember that 0 and   mean the same thing.

Test Cases
(Read I/O as top/left → bottom/right.)
Nand:
&amp;!

00/0 → 01/1
00/1 → 01/1
10/0 → 01/1
10/1 → 11/0
All ones:
1111
1\+\
1+\+
1\+\

Any input should result in 1111/1111.
Xor from Nand: (note the column of trailing spaces)
\)+\ 
U&amp;!&amp; 
+! ! 
\&amp;!&amp; 
   ! 

00000/00000 → 00000/00000
00000/10000 → 00010/00000
10000/00000 → 00010/00000
10000/10000 → 00000/00000
Zig zag:
+++\00000000
000\!!!!\000
00000000\+++

The first bit of the left input becomes the last bit of the right output. Everything else is 0.
000000000000/000 → 000000000000/000
000000000000/100 → 000000000000/001
Propagation:
)))
UUU
U+U
U+U
UUU

The first bit of the left input goes to all the outputs.
000/00000 → 000/00000
000/10000 → 111/11111
Here's a pastebin of all 1×1 grid test cases.
Scoring
The shortest submission in bytes wins.
Bonus: What cool &quot;circuits&quot; can you make?
P.S. Don't bother Googling &quot;duodyadic tiles&quot;. I made them up yesterday ;D
If you want to discuss expanding this idea into a full-fledged programming language, come to this chatroom.
C, 332 309 272 270 266 259 247 225 bytes

#define C(x)*c-x?
i,k,T,L,m;f(c,t,l)char*c,*t,*l;{while(L=l[i]){for(k=0;T=t[k];c++)L=C(49)C(43)C(92)C(85)C(41)C(33)C(38)C('|')C(94)T=48:(T^=L-48):(T|=L):(T&amp;=L):(T^=1,L^1):(T=L):T:(m=T,T=L,m):L:(T=49),t[k++]=T;c++;l[i++]=L;}}

View results online here!
This defines a function void f(char*, char*, char*), which should take the board as its first input, then the top row of input, and then the left row of input.
Here's what I used to test it:
#include &quot;stdio.h&quot;
int main() {
    char buf[1024],top[33],left[33];
    /* Copy and paste an example circuit as the first input,
       and put a 'Q' immediately after it. 
       Note that the Q is never touched by the function f, and is used
       solely as a delimiter for input. */
    scanf(&quot;%[^Q]Q &quot;,buf);
    /* Then enter your top inputs */
    scanf(&quot;%[01]%*[^01]&quot;, top);
    /* Then your left ones */
    scanf(&quot;%[01]&quot;, left);
    /* OUTPUT: Bottom\nRight */
    f(buf, top, left);
    return 0;
}

Thus, by inputting Sp3000's 2-bit multiplier:
UUUU))))
UU++)))&amp;
UUU+)  U
UU++&amp;))U
U++&amp;+)^U
U)&amp;\&amp;)UU
   U+^UU
   \&amp;UUUQ
11110000
00000000

We get:
00001001
11111111

On another note, with Sp3000's half adder in mind, I'd like to see a full adder... One of you guys did it! I don't think the system stands on its own as a programming language, but it's been very interesting. This seems like an excellent target for metagolf, though!
A Short Explanation:
Here's the unraveled, commented code:
/* We define the first half of the ?: conditional operator because, well,
   it appears over and over again. */
#define C(x)*c-x?
/* i,k are counting variables
   T,L are *current* top and left inputs */
i,k,T,L,m;
f(c,t,l)char*c,*t,*l;{
    /* The outer loop iterates from top to bottom over l and c */
    while(L=l[i]){
        /* Inner loop iterates from left to right over t and c */
        for(k=0;T=t[k];c++)
            /* This line looks awful, but it's just a bunch of character
            comparisons, and sets T and L to the output of the current c */
            L=C(49)C(43)C(92)C(85)C(41)C(33)C(38)C('|')C(94)T=48:(T^=L-48):(T|=L):(T&amp;=L):(T^=1,L^1):(T=L):T:(m=T,T=L,m):L:(T=49),
            /* Write our output to our input, it will be used for the next row */
            t[k++]=T;
        c++; /*Absorbs the newline at the end of every row */
        /* Keep track of our right-most outputs, 
        and store them in the handy string passed to the function. */
        l[i++]=L;
    }
    /* Bottom output is now stored entirely in t, as is right output in l */        
}

We iterate over c, left to right (then top to bottom), rewriting the t inputs each time and pushing out a right-most output which is shoved into the l string. We can imagine this as replacing the top row of c with 1's and 0's iteratively, and keeping track of the bits that are pushed out at the right.
Here's a more visual sequence, row by row:
 111                                  
1&amp;+^  =&gt;  110 -&gt;0  =&gt;     -&gt;0  =&gt;     0 Thus, &quot;01&quot; has been written to l,
1+&amp;+     1+&amp;+         110 -&gt;1         1
                                  110   And &quot;110&quot; is stored currently in t.

This obviously gets more complicated with different symbols and sizes, but the central idea holds. This works only because data never flows up or left.