GithubHelp home page GithubHelp logo

kobbled / tp_plus Goto Github PK

View Code? Open in Web Editor NEW
27.0 1.0 5.0 1.44 MB

FANUC TP abstraction

Home Page: http://github.com/kobbled/tp_plus

License: Apache License 2.0

Ruby 89.86% Yacc 8.11% C++ 0.94% LiveScript 0.12% Batchfile 0.04% HTML 0.93%
fanuc grammer parser roboguide ruby

tp_plus's Introduction

TP+

TP+ is a higher-level language abstraction that translates into FANUC TP. It features many useful utilities that makes creating TP programs easier:

  • Functions and inline functions
  • Importing numerous files
  • Namespacing
  • Variable declaration for registers, position registers, IO, etc.
  • Local variables
  • Readable motion statements
  • Streamlined position declaration
  • Position manipulation
  • Build the same program for multiple controllers through the use of environment files and imports
  • Managing Register sets on controller
  • Register and Postion ranges for easy declaration of blocks of registers
  • Preprocessor
  • Automatic label numbering
  • Improved looping
  • Easier managment of numerous TP files
  • Can be used with the package manager Rossum

This branch was forked from the archived repo TP+

[!NEW]

[!INFO]

  • see Features for a quick look at the features
  • see examples.md for an indepth introduction to TP+
  • Test example .tpp files can be found in ./examples directory of this repository

Install

Note

A Standalone .exe can be found in https://github.com/kobbled/tp_plus/releases, where you do not have to install anything. Simply add the location where the tpp.exe file resides onto your environment Path. However, with this method you will not recieve up to date changes to TP+.

  1. Install Ruby
  2. Install git
  3. Install bundler gem install bundler
  4. Clone the repo git clone https://github.com/kobbled/tp_plus.git
  5. move into tp_plus folder; cd tp_plus
  6. Install dependencies with bundle
  7. Build the parser and run the tests with bundle exec rake
  8. Make sure all tests pass
  9. Add full path of ./tp_plus/bin to your environment path
set PATH=%PATH%;\path\to\tp_plus\bin

[!INFO] Alternatively there is a docker image located in the docker-container branch. However due to Roboguide and Fanuc tools being windows only, the workflow is too awkward for the standard user and is not recommended. Furthermore, the build tools vscode-tpp-extension, and Rossum currently do not have docker interoperability support.

Updating

In a command prompt, or git shell run

git fetch && git pull
rake

Usage

print output to console:

tpp filename.tpp

print output to file (must be the same filename):

tpp filename.tpp -o filename.ls

interpret using an environment file:

tpp filename.tpp -e env.tpp

include folders:

tpp filename.tpp -i ../folder1 -i ../folder2

build karel hash table from environment file. The first argument is to specify the filename (without the extension) that the hash will be written to. The second argument specifies if you also want to clear the register values on execution of the karel program.

Warning

Setting to true will wipe the registers, position registers, and string registers from the controller

tpp filename.tpp -k 'karelFilename',false

See tpp --help for options.

[!INFO] All of these options can be accessed through vscode using the Fanuc TP-Plus Language Extension

[!INFO] All of these options can be specified in the Rossum package manager through the package.json file

Features

Pose Declarations

TP+ TP
TP_GROUPMASK = "1,*,*,*,*"
TP_COMMENT = "test prog"

p := P[1..6]

tool := UTOOL[5]
frame := UFRAME[3]

use_utool tool
use_uframe frame

#declare a default pose to set all positions to
#if they are not explicitly declared
default.group(1).pose -> [0, 0, 0, 0, 0 ,0]
default.group(1).config -> ['F', 'U', 'T', 0, 0, 0]

#declare joint pose
p1.group(1).joints -> [180, 23.2, 90.5, 0, 60.8, -90.5]
joint_move.to(p1).at(30, '%').term(-1)

#declare position
p2.group(1).pose -> [0,50,100,0,90,0]
p2.group(1).config -> ['F', 'U', 'T', 0, 0, 0]

#independently set position and orientation
p3.group(1).xyz -> [0,30,0]
p3.group(1).orient -> [90,0,0]
p3.group(1).config -> ['F', 'U', 'T', 0, 0, 0]

arc_move.to(p2).at(50, 'mm/s').term(100)
arc_move.to(p3).at(50, 'mm/s').term(100)

#batch declare poses, as well as apply offsets
(p4..p6).group(1).xyz.offset -> [0, 0 ,50]
linear_move.to(p4).at(50, 'mm/s').term(-1)
linear_move.to(p5).at(30, 'mm/s').term(100)
linear_move.to(p6).at(30, 'mm/s').term(-1)
/PROG TEST10
COMMENT = "test prog";
DEFAULT_GROUP = 1,*,*,*,*;
/MN
 : UTOOL_NUM=5 ;
 : UFRAME_NUM=3 ;
 :  ;
 : ! declare joint pose ;
 : J P[1:p1] 30% FINE ;
 :  ;
 : ! declare position ;
 :  ;
 : ! independently set position and ;
 : ! orientation ;
 :  ;
 : A P[2:p2] 50mm/sec CNT100 ;
 : A P[3:p3] 50mm/sec CNT100 ;
 :  ;
 : ! batch declare poses, as well as ;
 : ! apply offsets ;
 : L P[4:p4] 50mm/sec FINE ;
 : L P[5:p5] 30mm/sec CNT100 ;
 : L P[6:p6] 30mm/sec FINE ;
/POS
P[1:"p1"]{
   GP1:
  UF : 3, UT : 5,
    J1 = 180.000 deg, J2 = 23.200 deg, J3 = 90.500 deg,
    J4 = 0.000 deg, J5 = 60.800 deg, J6 = -90.500 deg};
P[2:"p2"]{
   GP1:
  UF : 3, UT : 5,  CONFIG : 'F U T, 0, 0, 0',
  X = 0.000 mm, Y = 50.000 mm, Z = 100.000 mm,
  W = 0.000 deg, P = 90.000 deg, R = 0.000 deg};
P[3:"p3"]{
   GP1:
  UF : 3, UT : 5,  CONFIG : 'F U T, 0, 0, 0',
  X = 0.000 mm, Y = 30.000 mm, Z = 0.000 mm,
  W = 90.000 deg, P = 0.000 deg, R = 0.000 deg};
P[4:"p4"]{
   GP1:
  UF : 3, UT : 5,  CONFIG : 'F U T, 0, 0, 0',
  X = 0.000 mm, Y = 30.000 mm, Z = 50.000 mm,
  W = 90.000 deg, P = 0.000 deg, R = 0.000 deg};
P[5:"p5"]{
   GP1:
  UF : 3, UT : 5,  CONFIG : 'F U T, 0, 0, 0',
  X = 0.000 mm, Y = 30.000 mm, Z = 100.000 mm,
  W = 90.000 deg, P = 0.000 deg, R = 0.000 deg};
P[6:"p6"]{
   GP1:
  UF : 3, UT : 5,  CONFIG : 'F U T, 0, 0, 0',
  X = 0.000 mm, Y = 30.000 mm, Z = 150.000 mm,
  W = 90.000 deg, P = 0.000 deg, R = 0.000 deg};
/END

Namespaces

TP+ TP
namespace ns1
  VAL1 := 1
  VAL2 := 2
end

namespace ns2
  VAL1 := 3.14
  VAL2 := 2.72
end

def test()
  using ns1, ns2

  foo := R[1]
  bar := R[2]
  foostr := SR[3]

  foo = ns1::VAL1
  bar = ns1::VAL2

  foostr = Str::set(ns2::VAL1)
  foo = ns3::test2()
end
/PROG TEST
COMMENT = "TEST";
DEFAULT_GROUP = *,*,*,*,*;
/MN
 :  ;
 :  ;
 : R[1:foo]=1 ;
 : R[2:bar]=2 ;
 :  ;
 : CALL STR_SET(3.14,3) ;
 : CALL NS3_TEST2(1) ;
/END

Functions

TP+ TP
namespace Math
  M_PI := 3.14159

  def arclength(ang, rad) : numreg
    return(ang*rad*M_PI/180)
  end

  def arcangle(len, rad) : numreg
    return(len/rad*180/M_PI)
  end
end

arclength := R[1]
arcangle := R[2]

arclength = Math::arclength(90, 85)
arcangle = Math::arclength(arclength, 85)
/PROG TEST
COMMENT = "TEST";
DEFAULT_GROUP = 1,*,*,*,*;
/MN
 : CALL MATH_ARCLENGTH(90,85,1) ;
 : CALL MATH_ARCLENGTH(R[1:arclength],85,2) ;
/POS
/END
/PROG MATH_ARCANGLE
COMMENT = "MATH_ARCANGLE";
DEFAULT_GROUP = *,*,*,*,*;
/MN
 : R[AR[3]]=(AR[1]/AR[2]*180/3.14159) ;
 : END ;
/END
/PROG MATH_ARCLENGTH
COMMENT = "MATH_ARCLENGTH";
DEFAULT_GROUP = *,*,*,*,*;
/MN
 : R[AR[3]]=(AR[1]*AR[2]*3.14159/180) ;
 : END ;
/END

Inline Functions

TP+ TP
namespace Math
  M_PI := 3.14159

  inline def arclength(ang, rad) : numreg
    return(ang*rad*M_PI/180)
  end

  inline def arcangle(len, rad) : numreg
    return(len/rad*180/M_PI)
  end
end

arclength := R[1]

arclength = Math::arclength(90, 85)
/PROG TEST
COMMENT = "TEST";
DEFAULT_GROUP = 1,*,*,*,*;
/MN
 : ! inline Math_arclength ;
 :  ;
 : R[1:arclength]=(90*85*3.14159/180) ;
 : ! end Math_arclength ;
 :  ;
/POS
/END

Importing Files

TP+ TP
import math_imp

arclength := R[30]
degress   := R[31]
radius    := R[32]

degress = 90
radius = 85

arclength = Math::arclength(degress, radius)

math_imp.tpp

namespace Math
  M_PI := 3.14159

  inline def arclength(ang, rad) : numreg
    return(ang*rad*M_PI/180)
  end

  inline def arcangle(len, rad) : numreg
    return(len/rad*180/M_PI)
  end
end
/PROG TEST
COMMENT = "TEST";
DEFAULT_GROUP = 1,*,*,*,*;
/MN
 :  ;
 : R[31:degress]=90 ;
 : R[32:radius]=85 ;
 :  ;
 : ! inline Math_arclength ;
 :  ;
 : R[30:arclength]=(R[31:degress]*R[32:radius]*3.14159/180) ;
 : ! end Math_arclength ;
 :  ;
/POS
/END

Local Variables

TP+ TP
local := R[50..70]

sum := LR[]

def ratio(ar1) :numreg
    divisor := LR[]

    if (ar1 % 2 == 0)
      divisor = 2
    else
      divisor = 1
    end

    return(ar1/divisor)
end

def addin() : numreg
    foo := LR[]
    bar := LR[]

    bar = multiple(bar)
    return(foo + bar)
end

def multiple(ar1) : numreg
    multiplier := LR[]

    multiplier = 10
    return(ar1*multiplier)
end

sum = addin()
sum = ratio()
/PROG TEST
COMMENT = "TEST";
DEFAULT_GROUP = 1,*,*,*,*;
/MN
 : CALL ADDIN(50) ;
 : CALL RATIO(50) ;
/POS
/END
/PROG ADDIN
COMMENT = "ADDIN";
DEFAULT_GROUP = *,*,*,*,*;
/MN
 :  ;
 : CALL MULTIPLE(R[52:bar],52) ;
 : R[AR[1]]=R[51:foo]+R[52:bar] ;
 : END ;
/END
/PROG MULTIPLE
COMMENT = "MULTIPLE";
DEFAULT_GROUP = *,*,*,*,*;
/MN
 :  ;
 : R[53:multiplier]=10 ;
 : R[AR[2]]=AR[1]*R[53:multiplier] ;
 : END ;
/END
/PROG RATIO
COMMENT = "RATIO";
DEFAULT_GROUP = *,*,*,*,*;
/MN
 :  ;
 : IF ((AR[1] MOD 2<>0)),JMP LBL[100] ;
 : R[51:divisor]=2 ;
 : JMP LBL[101] ;
 : LBL[100] ;
 : R[51:divisor]=1 ;
 : LBL[101] ;
 :  ;
 : R[AR[2]]=AR[1]/R[51:divisor] ;
 : END ;
/END

Expressions in Arguments

TP+ TP
local := R[70..80]

foo := R[10]
bar := R[11]
biz := R[12]
baz := R[13]

namespace Math
  PI := 3.14159

  def test(ar1, ar2, ar3) : numreg
    return(Math::test2(ar1, ar2)*(ar1+ar2+ar3))
  end

  def test2(ar1, ar2) : numreg
    if ar1 > ar2
      return(0.5)
    end

    return(1)
  end
end

foo = Math::ln(2)

foo = Math::test(5+3, bar*biz/2, -1*biz*Math::PI)

foo = Math::test(bar*biz/2, set_reg(biz), -1*biz*Math::PI)

foo = Math::test3(bar*Math::PI*set_reg(baz))
/PROG TEST
COMMENT = "TEST";
DEFAULT_GROUP = 1,*,*,*,*;
/MN
 : CALL MATH_LN(2,10) ;
 :  ;
 : R[70:dvar2]=5+3 ;
 : R[71:dvar3]=(R[11:bar]*R[12:biz]/2) ;
 : R[72:dvar4]=((-1)*R[12:biz]*3.14159) ;
 : CALL MATH_TEST(R[70:dvar2],R[71:dvar3],R[72:dvar4],10) ;
 :  ;
 : CALL SET_REG(R[12:biz],74) ;
 : R[73:dvar5]=(R[11:bar]*R[12:biz]/2) ;
 : R[75:dvar7]=((-1)*R[12:biz]*3.14159) ;
 : CALL MATH_TEST(R[73:dvar5],R[74:dvar6],R[75:dvar7],10) ;
 :  ;
 : CALL SET_REG(R[13:baz],76) ;
 : R[77:dvar9]=(R[11:bar]*3.14159*R[76:dvar8]) ;
 : CALL MATH_TEST3(R[77:dvar9],10) ;
/POS
/END
/PROG MATH_TEST
COMMENT = "MATH_TEST";
DEFAULT_GROUP = *,*,*,*,*;
/MN
 : CALL MATH_TEST2(AR[1],AR[2],78) ;
 : R[AR[4]]=(R[78:dvar1]*(AR[1]+AR[2]+AR[3])) ;
 : END ;
/END
/PROG MATH_TEST2
COMMENT = "MATH_TEST2";
DEFAULT_GROUP = *,*,*,*,*;
/MN
 : IF (AR[1]<=AR[2]),JMP LBL[100] ;
 : R[AR[3]]=0.5 ;
 : END ;
 : LBL[100] ;
 :  ;
 : R[AR[3]]=1 ;
 : END ;
/END

Preprocessor

With the ppr preprocessor things like conditional inclusion, file inclusion, text macros, executing internal ruby code is possible.

Below is an example of running a ruby script to output the arc motion path of a circle in TP.

TP+ TP
use_utool 3
use_uframe 2

TP_GROUPMASK = "1,1,*,*,*"
TP_STACK_SIZE = "600"

default.group(1).pose -> [0,0,0,90,180,0]
default.group(1).config -> ['F','U','T', 0, 0, 0]
default.group(2).joints -> [0]


.assign RADIUS :< 80
.assign INCREMENTS :< 20
.assign DISTANCE :< 100

.do
  #define points
  :< "p := P[1..#{@INCREMENTS}]"

  #set first point
  :< "joint_move.to(p1).at(15, '%').term(-1)\n"

  inc = @INCREMENTS.to_i
  degree = 0
  for i in 1..inc do
    #get degree
    degree = 360*(i-1)/(inc-1)
    :< "p#{i}.group(1).pose.polar.z -> [#{(-1*degree).to_s}, #{@RADIUS.to_s}, #{@DISTANCE.to_s}, 90, 180, 0]\n"
    :< "p#{i}.group(2).joints -> [#{(degree).to_s}]\n"
    :< "arc_move.to(p#{i}).at(50, 'mm/s').term(#{(i == 1 || i == inc) ? '-1' : '100'}).coord\n"
  end
.end
/PROG TEST41
/ATTR
COMMENT = "TEST41";
TCD:  STACK_SIZE	= 600,
      TASK_PRIORITY	= 50,
      TIME_SLICE	= 0,
      BUSY_LAMP_OFF	= 0,
      ABORT_REQUEST	= 0,
      PAUSE_REQUEST	= 0;
DEFAULT_GROUP = 1,1,*,*,*;
/APPL
/MN
 : UTOOL_NUM=3 ;
 : UFRAME_NUM=2 ;
 :  ;
 :  ;
 :  ;
 :  ;
 : J P[1:p1] 15% FINE ;
 : A P[1:p1] 50mm/sec FINE COORD ;
 : A P[2:p2] 50mm/sec CNT100 COORD ;
 : A P[3:p3] 50mm/sec CNT100 COORD ;
 : A P[4:p4] 50mm/sec CNT100 COORD ;
 : A P[5:p5] 50mm/sec CNT100 COORD ;
 : A P[6:p6] 50mm/sec CNT100 COORD ;
 : A P[7:p7] 50mm/sec CNT100 COORD ;
 : A P[8:p8] 50mm/sec CNT100 COORD ;
 : A P[9:p9] 50mm/sec CNT100 COORD ;
 : A P[10:p10] 50mm/sec CNT100 COORD ;
 : A P[11:p11] 50mm/sec CNT100 COORD ;
 : A P[12:p12] 50mm/sec CNT100 COORD ;
 : A P[13:p13] 50mm/sec CNT100 COORD ;
 : A P[14:p14] 50mm/sec CNT100 COORD ;
 : A P[15:p15] 50mm/sec CNT100 COORD ;
 : A P[16:p16] 50mm/sec CNT100 COORD ;
 : A P[17:p17] 50mm/sec CNT100 COORD ;
 : A P[18:p18] 50mm/sec CNT100 COORD ;
 : A P[19:p19] 50mm/sec CNT100 COORD ;
 : A P[20:p20] 50mm/sec FINE COORD ;
 :  ;
 :  ;
/POS
/END

Environment Files

You can save the robot controller configuration into an environment file. This can be swiched out depending on which robot you are using, and can be used to manage the register names on the controller (see: examples.md)

#----------
#Constants
#----------
FINE  :=  -1
CNT  := 100
PI    := 3.14159

#----------
#Frames
#----------
world        := UFRAME[1]
frame        := UFRAME[2]
tool         := UTOOL[1]

#----------
#Laser IO
#----------
Laser_Enable         := DO[1]
Laser_Ready          := DI[2]
Laser_On             := DO[3]

Laser_Power         :=  AO[1]

#----------
# User IO
#----------
system_ready    := UO[2]
Prgm_Run        := UO[3]
Prgm_Pause      := UO[4]

#-----------
# HMI Flags
#-----------
Hmi_Start            := F[1]
Hmi_Stop             := F[2]
Hmi_Laser_Enable        := F[3]
Hmi_Laser_Disable       := F[4]

#----------
#Program Registers
#----------
program_name := SR[1]

Alarm_Reg       := R[1]
Mem_Tool_No     := R[2]
Mem_Frame_No    := R[3]

j := R[50]
passes := R[51]
l := R[52]
layers := R[53]


#----------
#Workstations
#----------

namespace Headstock
  frame := UTOOL[2]
  select := F[38]
  home := PR[3]
.def Headstock_GROUP :< 2
.def Headstock_DIRECTION :< -1

end

namespace Positioner
  frame := UTOOL[3]
  select := F[37]
  home := PR[4]
.def Positioner_GROUP :< 3
.def Positioner_DIRECTION :< 1

end

#----------
#EEF Tools
#----------
namespace Tool1
  frame := UTOOL[1]
  read_pin := AI[1]
  interupt_pin := DI[8]
  SEARCH_DIST := 10
  SEARCH_SPEED := 3
end

namespace Tool2
  frame := UTOOL[3]
  read_pin := AI[2]
  interupt_pin := DI[10]
  SEARCH_DIST := 50
  SEARCH_SPEED := 6
end

#----------
#LAM Parameters
#----------
namespace Lam
  power          := R[60]
  flowrate       := R[26]
  speed          := R[61]
  strt           := DO[3]
  enable         := DO[1]
end

# ----------
# local variables
# -----------
local         := R[250..300]
local         := PR[80..100]

Documentation

Build rdocs with:

rake rdoc

License

TP+ is released under the MIT License.

tp_plus's People

Contributors

dickvand avatar groupsixtech avatar halmusaibeli avatar kobbled avatar unreal avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

tp_plus's Issues

Add functions

export each function as a different ls file with function name, except for the main function, export that as the program name.

If / then / endif conversion failure

The conversion of

if foo == 1 then
 # do something
end

gives an ENDIF with two semicolons:

 : IF (R[1:foo]=1) THEN ;
 : ! do something ;
 : ENDIF ; ;

That second semicolon gives an error when importing the file to Fanuc.

inline functions

conversion example

# MAIN

inline def arclength(angle, radius) : numreg 
  return(angle*radius*M_PI/180)
end

length := R[1]
length2 := R[2]
length3 := R[3]
radius := R[4]
angle := R[5]

length = arclength(90, 100)
length2 = arclength(180, 50)
length3 = arclength(angle, radius)
: ! MAIN ;
: R[1:length]=(90*100*3.14159/180) ;
: R[2:length2]=(180*50*3.14159/180) ;
: R[3:length3]=(R[5:angle]*R[4:radius]*3.14159/180) ;
: END ;

Would have to convert argument registers to the actual parent call input arguments. It would also have to interpret returns to map them to the set output registers.

Modifiers that still need to be added

Section 7.3 of Handling Tool Manual
-Corner Region Termination (CRy)
-Corner Distance (CDy)
-Approach Linear Distance (AP_LDx)
-Retract Linear Distance (RT_LDx)
-Process Speed (PSPDx)
-Continuous Rotation Velocity (CTVx)
-Simultaneous Extended Axis Velocity (EVx%)
-Independent Extended Axis Velocity (Ind.EVx%)
-Remote TCP motion (RTCP)
-Search Motion Option (Search [ ])
-Distance Before (DB xmm, prog)
-'POINT LOGIC' for use in TA,TB,DB statements

Cannot interpret nested call statements in return

local := R[70..80]

def func2(val, exp) : numreg
  return(Mth::exp(exp * Mth::ln(val)))
end

power := R[20]
power = ns1::func2(4, 2)

gives error:

indirect_node.rb:70:in `id': undefined method `value' for #<TPPlus::Nodes::ArgumentNode:0x000001f424c699f8 @id=3, @comment=:ret> (NoMethodError)

        @target.value\r

add local scope variables

utilize a block of designated registers and position registers to use as local variables in functions, that get released once out of scope.

Multiple returns statement

tp+

def circleCenter3Points(x1,y1,z1,x2,y2,z2,x3,y3,z3) : numreg, numreg, numreg
    a = x1 * (y2 - y3) - y1 * (x2 - x3) + x2 * y3 - x3 * y2
    b = (Mth::pow(x1, 2) + Mth::pow(y1, 2)) * (y3 - y2)
    c = (Mth::pow(x1, 2) + Mth::pow(y1, 2)) * (x2 - x3)
    d = (Mth::pow(x3, 2) + Mth::pow(y3, 2)) * (x2 * y1 - x1 * y2)
    
    x = -b / (a * 2) 
    y = -c / (a * 2)    
    z = (z1+z2+z3)/3

   return(x, y, z)
end

center := R[30..33]

center = circleCenter3Points(X1,Y1,Z1,X2,Y2,Z3,X3,Y3,Z3)

LS would turn into

/MN
 : CALL CIRCLECENTER3POINTS(X1,Y1,Z1,X2,Y2,Z3,X3,Y3,Z3,30,31,32) ;
/END
/MN
 : R[50:a]=(AR[1]*(AR[5]-AR[8])-AR[2]*(AR[4]-AR[7])+AR[4]*AR[8]-AR[7]*AR[5]) ;
 : CALL MTH_POW(AR[1],2,57) ;
 : CALL MTH_POW(AR[2],2,58) ;
 : R[51:b]=((R[57:dvar1]+R[58:dvar2])*(AR[8]-AR[5])) ;
 : CALL MTH_POW(AR[1],2,59) ;
 : CALL MTH_POW(AR[2],2,60) ;
 : R[52:c]=((R[59:dvar3]+R[60:dvar4])*(AR[4]-AR[7])) ;
 : CALL MTH_POW(AR[7],2,61) ;
 : CALL MTH_POW(AR[8],2,62) ;
 : R[53:d]=((R[61:dvar5]+R[62:dvar6])*(AR[4]*AR[2]-AR[1]*AR[5])) ;
 :  ;
 : R[54:x]=(R[51:b]*(-1)/(R[50:a]*2)) ;
 : R[55:y]=(R[52:c]*(-1)/(R[50:a]*2)) ;
 : R[56:z]=((AR[3]+AR[6]+AR[9])/3) ;

 : ! Multiple return ;
 : R[AR[10]]=R[54:x] ;
 : R[AR[11]]=R[55:y] ;
 : R[AR[12]]=R[56:z] ;
/END

Namespace functions to self are not recognized

In trying to inline a member function within another member function, the namespace function does not recognize itself, or it other functions to check if it should inline the function call.

namespace ns
  inline def func1()
     # do work
     return()
  end

  inline def func2()
     #this function doesn't inline
     func1()
    
    return()
  end
end

A namespace should have reference to self i.e.

 inline def func2()
     using self

     func1()
  end

self should be implicit for all functions using scoping declaration

Expression expansion doesn't reuse local registers after completed

e.g.:

local := R[50..90]
a = x1 * (y2 - y3) - y1 * (x2 - x3) + x2 * y3 - x3 * y2
b = (Mth::pow(x1, 2) + Mth::pow(y1, 2)) * (y3 - y2)
c = (Mth::pow(x1, 2) + Mth::pow(y1, 2)) * (x2 - x3)
d = (Mth::pow(x3, 2) + Mth::pow(y3, 2)) * (x2 * y1 - x1 * y2)

expands to this in LS:

 : R[50:a]=(AR[1]*(AR[5]-AR[8])-AR[2]*(AR[4]-AR[7])+AR[4]*AR[8]-AR[7]*AR[5]) ;
 : CALL MTH_POW(AR[1],2,57) ;
 : CALL MTH_POW(AR[2],2,58) ;
 : R[51:b]=((R[57:dvar1]+R[58:dvar2])*(AR[8]-AR[5])) ;
 : CALL MTH_POW(AR[1],2,59) ;
 : CALL MTH_POW(AR[2],2,60) ;
 : R[52:c]=((R[59:dvar3]+R[60:dvar4])*(AR[4]-AR[7])) ;
 : CALL MTH_POW(AR[7],2,61) ;
 : CALL MTH_POW(AR[8],2,62) ;
 : R[53:d]=((R[61:dvar5]+R[62:dvar6])*(AR[4]*AR[2]-AR[1]*AR[5])) ;

After the evaluation of b, the stack counter should be reset to 57. This can be achieved by doing $stack.push/$stack.pop before/after each expression expansion.

Dockerfile

Create dockerfile. Apparently ruby3 has issues in a docker container. Possibly downgrade back to ruby2, or branch until issue is resolved.

Position Setting Features

  • offset -> p2.group(1).xyz.offset -> [0,0,10] Use to offset from the previous position
  • copy positions p2 = p1
  • range sets -> p1..p3.group(1).xyz -> [10,0,100]
  • reverse -> p6..p10 = p1..p5.reverse copy positions into next set in reverse order
  • polar -> transform cylindrical (theta, r, z) data into cartesian
  • sphere -> transform spherical (r, theta, phi) data into cartesian
  • translate whole or individual positions program (similar to program shift). -> translate.group(1).pose(0,0,100,0,0,0)

Motion Modifiers

I believe that there is some handling of motion modifiers but there are no examples of the syntax required. I specifically need to know how to add "MROT" to a joint move.

Inlining self members is not working

Calling members from the same namespace and trying to inline them does not work:

TP+

local := R[50..80]

namespace Calc

  inline def normalizeVector(n1,n2,n3,e1,e2,e3)
    norm := LR[]
    
    norm = Mth::SQRT(n1*n1 + n2*n2 + n3*n3)
    indirect('r', e1) = n1/norm
    indirect('r', e2) = n2/norm
    indirect('r', e3) = n3/norm
  end

  inline def dot(nx,ny,nz,vx,vy,vz,d)
      indirect('r', d) = nx*vx + ny*vy + nz*vz
  end

  inline def intersect(x1,y1,z1,x2,y2,z2,nx,ny,nz)
    ux := LR[]
    uy := LR[]
    uz := LR[]
    vx := LR[]
    vy := LR[]
    vz := LR[]
    d  := LR[]

    # vector from two points
    vx=x2-x1
    vy=y2-y1
    vz=z2-z1

    Calc::normalizeVector(vx,vy,vz,&ux,&uy,&uz)  # unit vector
    d = Calc::dot(nx,ny,nz,ux,uy,uz)  # dot product
  end
end

X1 := -0.30694321232747335
Y1 := 1.6723049456001353
Z1 := 1.432745154010752
X2 := -0.7868785787889008
Y2 := 1.7975569490378929
Z2 := 1.44473503116485
CX := -0.23966969549655914
CY := 1.6529096364974976
CZ := 1.438263177871704

Calc::intersect(X1,Y1,Z1,X2,Y2,Z2,CX,CY,CZ)

Add position data helper tools

  • converts ls -> tpp for positions
  • make position data less verbose. (only have to define uframe, utool, config once, or once per change)
  • split components into position , and orientation. Make so that they persist for subsequent poses until changed.
  • include easy csv conversion "x,y,z,w,p,r, N, D, T, 0 ,0 ,0" to more easily write positions.
  • make tpp accept ls position data syntax so that you can just copy and paste the position data into tpp.

Call functions in expression only work for num registers

There is currently no way to tell if the return of a call statement in a expression is a posreg, or a numreg, due to handle_arg_funcs in CallNode being evaluated during parsing, before the functions are evaluated, and the return type of a function is decided. Also the preprocessing of local variables is done before funtions.

# first pass
      #---------
      #set a list of declared positions into @pose_list
      #populate_pose_set
      #create definitions from ranges
      traverse_nodes(@nodes, :preprocess_local_variables)

      # second pass
      #----------
      #prepare/allocate functions
      traverse_nodes(@nodes, :preprocess_functions)

This may have to be switched around in order for this issue to be resolved.

tpp can't compile more than one call of inlined functions

When more than one call of an inlined function exists in the same file, the tpp will throw an error when compiling as follows.

FAILED: C:/Users/HamdanAl-Musaibeli/workhub/myhub/sensing_tpp/build/G1_UFRAME_CALIBRATE.ls 
"C:\Users\HamdanAl-Musaibeli\workhub\shrdhub\pub\tp_plus\bin\tpp.bat" C:\Users\HamdanAl-Musaibeli\workhub\myhub\sensing_tpp\src\G1_UFRAME_CALIBRATE.tpp -o C:\Users\HamdanAl-Musaibeli\workhub\myhub\sensing_tpp\build\G1_UFRAME_CALIBRATE.ls -e "C:\Users\HamdanAl-Musaibeli\workhub\myhub\sensing_tpp\temp\env2.tpp" /I"C:\Users\HamdanAl-Musaibeli\workhub\myhub\sensing_tpp\include" 
default position not set! May give unintended results! Check position data before running!
C:/Users/HamdanAl-Musaibeli/workhub/shrdhub/pub/tp_plus/lib/tp_plus/function.rb:172:in `block in preinline': undefined method `identifier' for #<TPPlus::Nodes::DigitNode:0x000001ca6c88d668 @value=3, @name=""> (NoMethodError)

              map[v.identifier] = map[k]
                   ^^^^^^^^^^^
        from C:/Users/HamdanAl-Musaibeli/workhub/shrdhub/pub/tp_plus/lib/tp_plus/function.rb:167:in `each'
        from C:/Users/HamdanAl-Musaibeli/workhub/shrdhub/pub/tp_plus/lib/tp_plus/function.rb:167:in `preinline'
        from C:/Users/HamdanAl-Musaibeli/workhub/shrdhub/pub/tp_plus/lib/tp_plus/nodes/call_node.rb:159:in `eval'
        from C:/Users/HamdanAl-Musaibeli/workhub/shrdhub/pub/tp_plus/lib/tp_plus/nodes/conditional_node.rb:56:in `block in string_for'
        from C:/Users/HamdanAl-Musaibeli/workhub/shrdhub/pub/tp_plus/lib/tp_plus/nodes/conditional_node.rb:56:in `each'
        from C:/Users/HamdanAl-Musaibeli/workhub/shrdhub/pub/tp_plus/lib/tp_plus/nodes/conditional_node.rb:56:in `inject'
        from C:/Users/HamdanAl-Musaibeli/workhub/shrdhub/pub/tp_plus/lib/tp_plus/nodes/conditional_node.rb:56:in `string_for'
        from C:/Users/HamdanAl-Musaibeli/workhub/shrdhub/pub/tp_plus/lib/tp_plus/nodes/conditional_node.rb:22:in `true_block'
        from C:/Users/HamdanAl-Musaibeli/workhub/shrdhub/pub/tp_plus/lib/tp_plus/nodes/conditional_node.rb:89:in `eval'
        from C:/Users/HamdanAl-Musaibeli/workhub/shrdhub/pub/tp_plus/lib/tp_plus/nodes/conditional_node.rb:56:in `block in string_for'
        from C:/Users/HamdanAl-Musaibeli/workhub/shrdhub/pub/tp_plus/lib/tp_plus/nodes/conditional_node.rb:56:in `each'
        from C:/Users/HamdanAl-Musaibeli/workhub/shrdhub/pub/tp_plus/lib/tp_plus/nodes/conditional_node.rb:56:in `inject'
        from C:/Users/HamdanAl-Musaibeli/workhub/shrdhub/pub/tp_plus/lib/tp_plus/nodes/conditional_node.rb:56:in `string_for'
        from C:/Users/HamdanAl-Musaibeli/workhub/shrdhub/pub/tp_plus/lib/tp_plus/nodes/conditional_node.rb:38:in `false_block'
        from C:/Users/HamdanAl-Musaibeli/workhub/shrdhub/pub/tp_plus/lib/tp_plus/nodes/conditional_node.rb:98:in `eval'
        from C:/Users/HamdanAl-Musaibeli/workhub/shrdhub/pub/tp_plus/lib/tp_plus/interpreter.rb:406:in `block in eval'
        from C:/Users/HamdanAl-Musaibeli/workhub/shrdhub/pub/tp_plus/lib/tp_plus/interpreter.rb:399:in `each'
        from C:/Users/HamdanAl-Musaibeli/workhub/shrdhub/pub/tp_plus/lib/tp_plus/interpreter.rb:399:in `eval'
        from C:/Users/HamdanAl-Musaibeli/workhub/shrdhub/pub/tp_plus/bin/tpp:192:in `<main>'
ninja: build stopped: subcommand failed.

Add Independent and Simultaneous motion group instructions

Independent motion

linear_move.to(p1).at(100, 'mm/s').term(100).independent(group(1))
joint_move.to(p1).at(100, '%').term(50).independent(group(3))
Independent GP
GP1 L P[1] 50mm/s CNT100
GP3 J P[1] 100% CNT50

simultaneous motion

linear_move.to(p1).at(90, 'mm/s').term(100).simultaneous(group(1))
joint_move.to(p1).at(100, '%').term(50).simultaneous(group(3))
Simultaneous GP
GP1 L P[1] 90mm/s CNT100
GP3 J P[1] 100% CNT50

Pass namespaces in parent scope into functions

related to #23

need functionality for imports to work

namespace idhead
    SLOPE := -0.7457
    INTERCEPT := 41.537
    OFFSET := -0.4
  end

def frame_offset(frame, standoff)
   frame.x += (idhead::SLOPE*standoff + idhead::INTERCEPT)+idhead::OFFSET
end

Use LS position formatting in position_data section

Replace old json data

but parse into pose_factory.rb for error checking and saving state

position_data {
P[1:"p1"]{
   GP1:
  UF : 3, UT : 5,  CONFIG : 'F U T, 0, 0, 0',
  X = 0.000 mm, Y = 50.000 mm, Z = 0.000 mm,
  W = 0.000 deg, P = 0.000 deg, R = 0.000 deg
   GP2:
  UF : 3, UT : 5,
  J1 = 0.000 deg,
  J2 = 0.000 deg
     GP3:
  UF : 3, UT : 5,
  J1 = 500.000 mm
  };
P[2:"p2"]{
   GP1:
  UF : 3, UT : 5,  CONFIG : 'F U T, 0, 0, 0',
  X = 0.000 mm, Y = 50.000 mm, Z = 100.000 mm,
  W = 90.000 deg, P = 0.000 deg, R = -90.000 deg
   GP2:
  UF : 3, UT : 5,
  J1 = 90.000 deg,
  J2 = 0.000 deg
     GP3:
  UF : 3, UT : 5,
  J1 = 500.000 mm
  };
}
end

Issues with Ruby 3.1.1

While building the parser

Calling `DidYouMean::SPELL_CHECKERS.merge!(error_name => spell_checker)' has been deprecated. Please call `DidYouMean.correct_error(error_name, spell_checker)' instead.
Calling `DidYouMean::SPELL_CHECKERS.merge!(error_name => spell_checker)' has been deprecated. Please call `DidYouMean.correct_error(error_name, spell_checker)' instead.
racc -l -t -v -o lib/tp_plus/parser.rb generators/parser.y
Calling `DidYouMean::SPELL_CHECKERS.merge!(error_name => spell_checker)' has been deprecated. Please call `DidYouMean.correct_error(error_name, spell_checker)' instead.
1 useless nonterminals
2 useless rules
32 shift/reduce conflicts
3 reduce/reduce conflicts
C:/Ruby31-x64/bin/ruby.exe -w -I"lib;test" -I"C:/Ruby31-x64/lib/ruby/gems/3.1.0/gems/rake-12.3.3/lib" "C:/Ruby31-x64/lib/ruby/gems/3.1.0/gems/rake-12.3.3/lib/rake/rake_test_loader.rb" "test/test_helper.rb" "test/tp_plus/test_interpreter.rb" "test/tp_plus/test_parser.rb" "test/tp_plus/test_scanner.rb"
C:/Ruby31-x64/lib/ruby/gems/3.1.0/gems/bundler-2.1.4/lib/bundler/vendor/thor/lib/thor/error.rb:105: warning: constant DidYouMean::SPELL_CHECKERS is deprecated
Calling `DidYouMean::SPELL_CHECKERS.merge!(error_name => spell_checker)' has been deprecated. Please call `DidYouMean.correct_error(error_name, spell_checker)' instead.
tp_plus/lib/tp_plus/motion/pose_templates.rb:84: warning: mismatched indentations at 'end' with 'module' at 1

File does not exist: matrix

rake aborted!
Command failed with status (1): [ruby -w -I"lib;test" -I"C:/Ruby31-x64/lib/ruby/gems/3.1.0/gems/rake-12.3.3/lib" "C:/Ruby31-x64/lib/ruby/gems/3.1.0/gems/rake-12.3.3/lib/rake/rake_test_loader.rb" "test/test_helper.rb" "test/tp_plus/test_interpreter.rb" "test/tp_plus/test_parser.rb" "test/tp_plus/test_scanner.rb" ]

Tasks: TOP => default => test
(See full trace by running task with --trace)

and while interpreting

tp_plus/lib/tp_plus/motion/pose_factory.rb:449: warning: Passing safe_level with the 2nd argument of ERB.new is deprecated. Do not use it, and specify other arguments as keyword arguments.
tp_plus/lib/tp_plus/motion/pose_factory.rb:449: warning: Passing trim_mode with the 3rd argument of ERB.new is deprecated. Use keyword argument like ERB.new(str, trim_mode: ...) instead.

Issue with case statement

Hi Matt,
I've got some issues with the case statement. It seems that the 'else' statement is mandatory, since it throws an error there is no else case.

    case SubProgram
    when 1
        # case 1
    when 2
        # case 2
    end

Error:

Traceback (most recent call last):
        7: from C:/Users/d.vandodeweerd/tp_plus/bin/tpp:66:in `<main>'
        6: from C:/Users/d.vandodeweerd/tp_plus/lib/tp_plus/interpreter.rb:121:in `list_warnings'
        5: from C:/Users/d.vandodeweerd/tp_plus/lib/tp_plus/interpreter.rb:89:in `find_warnings'
        4: from C:/Users/d.vandodeweerd/tp_plus/lib/tp_plus/interpreter.rb:89:in `each'
        3: from C:/Users/d.vandodeweerd/tp_plus/lib/tp_plus/interpreter.rb:93:in `block in find_warnings'
        2: from C:/Users/d.vandodeweerd/tp_plus/lib/tp_plus/interpreter.rb:103:in `find_warnings'
        1: from C:/Users/d.vandodeweerd/tp_plus/lib/tp_plus/interpreter.rb:103:in `each'
C:/Users/d.vandodeweerd/tp_plus/lib/tp_plus/interpreter.rb:104:in `block in find_warnings': undefined method `get_block' for nil:NilClass (NoMethodError)

Second issue: when I use the case statement inside a function, I get an error too:

def test()
    case SubProgram
    when 1
        # case 1
    when 2
        # case 2
    else
        # else
    end
end

Error:

Traceback (most recent call last):
        12: from C:/Users/d.vandodeweerd/tp_plus/bin/tpp:103:in `<main>'
        11: from C:/Users/d.vandodeweerd/tp_plus/lib/tp_plus/interpreter.rb:135:in `output_functions'
        10: from C:/Users/d.vandodeweerd/tp_plus/lib/tp_plus/interpreter.rb:135:in `each'
         9: from C:/Users/d.vandodeweerd/tp_plus/lib/tp_plus/interpreter.rb:136:in `block in output_functions'        
         8: from C:/Users/d.vandodeweerd/tp_plus/lib/tp_plus/function.rb:77:in `output_program'
         7: from C:/Users/d.vandodeweerd/tp_plus/lib/tp_plus/interpreter.rb:200:in `eval'
         6: from C:/Users/d.vandodeweerd/tp_plus/lib/tp_plus/interpreter.rb:200:in `each'
         5: from C:/Users/d.vandodeweerd/tp_plus/lib/tp_plus/interpreter.rb:204:in `block in eval'
         4: from C:/Users/d.vandodeweerd/tp_plus/lib/tp_plus/nodes/case_node.rb:79:in `eval'
         3: from C:/Users/d.vandodeweerd/tp_plus/lib/tp_plus/nodes/case_node.rb:26:in `first_cond_statement'
         2: from C:/Users/d.vandodeweerd/tp_plus/lib/tp_plus/nodes/case_condition_node.rb:39:in `eval'
         1: from C:/Users/d.vandodeweerd/tp_plus/lib/tp_plus/nodes/case_condition_node.rb:26:in `is_jump_label'       
C:/Users/d.vandodeweerd/tp_plus/lib/tp_plus/nodes/jump_node.rb:17:in `eval': Label (caselbl1) not found (RuntimeError)
        6: from C:/Users/d.vandodeweerd/tp_plus/bin/tpp:103:in `<main>'
        5: from C:/Users/d.vandodeweerd/tp_plus/lib/tp_plus/interpreter.rb:135:in `output_functions'
        4: from C:/Users/d.vandodeweerd/tp_plus/lib/tp_plus/interpreter.rb:135:in `each'
        3: from C:/Users/d.vandodeweerd/tp_plus/lib/tp_plus/interpreter.rb:136:in `block in output_functions'
        2: from C:/Users/d.vandodeweerd/tp_plus/lib/tp_plus/function.rb:77:in `output_program'
        1: from C:/Users/d.vandodeweerd/tp_plus/lib/tp_plus/interpreter.rb:192:in `eval'
C:/Users/d.vandodeweerd/tp_plus/lib/tp_plus/interpreter.rb:219:in `rescue in eval': Runtime error on line 1: (RuntimeError)

These issues are not very urgent, because I can work around them, it is just to let you know.

Kind regards,
Dick

import files

add functionality to import other files with

using math, system, etc...

could use gpp preprocessor similar to ktransw for full preprocessor directives

Include singularity avoidance option in header

We use the singularity avoidance option most of the time, therefore it is needed to include the following statement in the LS-file's header:

/APPL

AUTO_SINGULARITY_HEADER;
  ENABLE_SINGULARITY_AVOIDANCE   : TRUE;

This should be between the DEFAULT_GROUP and the /MN line. I think it would be useful if we could set or unset this option from the tpp file.
I have solved it for now by adding the lines manually in the bin\tpp file, so there is no need for hurry.

Local posreg does not recognize the global default pose config

The local register seems to use a different group configuration instead of the default. Here is an example.

import Tasks

#constents
GRIPPER_DEPTH := 75
PPC := 3   # points per circle


#variables
    part_rad        := LR[]
    farCir_pos      := LR[]
    closeCir_pos    := LR[]
    part2tof_dist   := LR[]
    centers         := LR[]

#end of variables


#user input:

    # workpiece information
    PART_DIA := 153
    PART_LEN := 576
    part_rad = PART_DIA/2

    # far and close circles positions
    FARCIR      := 10   #mm wrt part edge
    CLOSECIR    := 10   #mm wrt gripper edge

    #for approach target calculation
    farCir_pos = PART_LEN - (GRIPPER_DEPTH + FARCIR)
    closeCir_pos = farCir_pos - CLOSECIR

    # robot pose approach
    CLEARANCE := 0.03             # initial clearance between part and tof with respect to measure frame
    TOFAPPROACH_ANGLE := 0        # with respect to tof measure frame
    part2tof_dist = PART_DIA/2 + CLEARANCE

#end of user input


#preprocessing section

    # getting robot ready
    TP_GROUPMASK = "1,*,*,*,*"
    TP_COMMENT = "3D tcp correction"
    
    zero_pos := P[1]

    default.group(1).pose -> [0, 0, 0, 0, 0 ,0]
    default.group(1).config -> ['N', 'U', 'T', 0, 0, 0]

    #safe_pos := PR[12]

    #move to safe pose
    #joint_move.to(safe_pos).at(30, '%').term(FINE)


    # clear tool offset
    Pos::clrpr(&tool_ofset)

    #check safe pos
    #G0_SAFE_POS()

    #rotate J1 to 95 deg
    #G1_ROTT_J1(95)

    #G0_DOOR_OPEN()

    dummypr1 = base_gripper
    part_frame = dummypr1

    # move into approach
    use_uframe tcp_calib_frame
    use_utool base_gripper

#end of perprocessing section


#approach tof
Tasks::appro_tof(TOFAPPROACH_ANGLE, part2tof_dist, farCir_pos)

For the tasks module, it contains a local posreg which should have (NUT) config but instead uses (NBU) config.

    def appro_tof(tofApproach_angle, part2tof_dist, farCir)
        # perform proper robot motion to approach the tof sensor, until surface is at zero with respect to
        # the tof measure frame. This motion is only on the z-axis.

        TP_GROUPMASK = "1,*,*,*,*"

        #vars
        pr1 := LPR[]

        # building target approach pose for the first time only
        # when correcting for the second time we use initial pose
        #if not len(self.initCloseTrgt):
        pr1 = Pos::setxyz(-1*part2tof_dist, 0, -1*farCir, tofApproach_angle, 0, 0)
        
        #move to the target
        joint_move.to(pr1).at(20, '%').term(FINE)
    end

But it will work if we use and initialize global posreg as in this code:

    def appro_tof(tofApproach_angle, part2tof_dist, farCir)
        # perform proper robot motion to approach the tof sensor, until surface is at zero with respect to
        # the tof measure frame. This motion is only on the z-axis.

        TP_GROUPMASK = "1,*,*,*,*"

        #vars
        pr1 := P[60]
        pr1.group(1).pose -> [0, 0, 0, 0, 0 ,0]
        pr1.group(1).config -> ['N', 'U', 'T', 0, 0, 0]

        # building target approach pose for the first time only
        # when correcting for the second time we use initial pose
        #if not len(self.initCloseTrgt):
        pr1 = Pos::setxyz(-1*part2tof_dist, 0, -1*farCir, tofApproach_angle, 0, 0)
        
        #move to the target
        joint_move.to(pr1).at(20, '%').term(FINE)
    end

indirect and inline functions

When using the indirect function inside the inlined function. The output PR has to be attached to the end of the function call and pointing to the PR number. See the example below.

Not working:
pr6 = correctFrame(&pr4, &pr5, Calib::Z) -- > PR[PR[86]]=PR[61:dummy_pr1] ;

Working:
correctFrame(&pr4, &pr5, Calib::Z, &pr6) -- > PR[86]=PR[61:dummy_pr1] ;

Environmental declarations not working in functions

Environmental file:

reg1 := R[1]

Function declaration:

def foo()
  reg1 = 1
end

Results in this error:

C:/Users/184/TP-plus/tp_plus/lib/tp_plus/interpreter.rb:214:in `rescue in eval': Runtime error on line 1: (RuntimeError)
Variable (reg1) not defined
        from C:/Users/184/TP-plus/tp_plus/lib/tp_plus/interpreter.rb:177:in `eval'
        from C:/Users/184/TP-plus/tp_plus/lib/tp_plus/function.rb:165:in `output_program'
        from C:/Users/184/TP-plus/tp_plus/lib/tp_plus/interpreter.rb:121:in `block in output_functions'
        from C:/Users/184/TP-plus/tp_plus/lib/tp_plus/interpreter.rb:120:in `each'
        from C:/Users/184/TP-plus/tp_plus/lib/tp_plus/interpreter.rb:120:in `output_functions'
        from C:/Users/184/TP-plus/tp_plus/bin/tpp:128:in `<main>'
C:/Users/184/TP-plus/tp_plus/lib/tp_plus/base_block.rb:123:in `get_var': Variable (reg1) not defined (RuntimeError)
        from C:/Users/184/TP-plus/tp_plus/lib/tp_plus/nodes/var_node.rb:10:in `target_node'
        from C:/Users/184/TP-plus/tp_plus/lib/tp_plus/nodes/var_node.rb:35:in `eval'
        from C:/Users/184/TP-plus/tp_plus/lib/tp_plus/nodes/assignment_node.rb:44:in `identifier_string'
        from C:/Users/184/TP-plus/tp_plus/lib/tp_plus/nodes/assignment_node.rb:55:in `eval'
        from C:/Users/184/TP-plus/tp_plus/lib/tp_plus/interpreter.rb:199:in `block in eval'
        from C:/Users/184/TP-plus/tp_plus/lib/tp_plus/interpreter.rb:195:in `each'
        from C:/Users/184/TP-plus/tp_plus/lib/tp_plus/interpreter.rb:195:in `eval'
        from C:/Users/184/TP-plus/tp_plus/lib/tp_plus/function.rb:165:in `output_program'
        from C:/Users/184/TP-plus/tp_plus/lib/tp_plus/interpreter.rb:121:in `block in output_functions'
        from C:/Users/184/TP-plus/tp_plus/lib/tp_plus/interpreter.rb:120:in `each'
        from C:/Users/184/TP-plus/tp_plus/lib/tp_plus/interpreter.rb:120:in `output_functions'
        from C:/Users/184/TP-plus/tp_plus/bin/tpp:128:in `<main>'

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.