Problem yacc in golang: syntax error: unexpected $end - go

A cordial greeting.
I'm learning yacc in golang and i created this file:
%{
package main
import (
"fmt"
)
%}
%union{
ex string
}
%token <ex> DB OTHER_DB
%%
query: other
|
db
;
db: DB
{
fmt.Printf("\tDB: %s\n", $1 )
}
;
other: OTHER_DB
{
fmt.Printf("\tOTHER_DB: %s\n", $1 )
}
;
%%
type mlex struct {
expr string
result int
}
func (f *mlex) Lex(lval *yySymType) int {
yyErrorVerbose = true
return 0
}
func (f *mlex) Error(s string) {
fmt.Printf("syntax error: %s\n", s)
}
func Parse(expr string) int {
m := &mlex{expr, 0}
yyParse(m)
return m.result
}
but when executing it I get this error:
syntax error: syntax error: unexpected $end, expecting DB or OTHER_DB
I have been testing this yacc file with this code:
package main
import (
"fmt"
)
func main() {
res := Parse("db")
fmt.Println(res)
}
What could it be ? Will I need anything else in the yacc file?
I am trying to make a very simple, fully functional example to understand it well.
Thanks for your time.

When your parser needs to know what the next input symbol ("token") is, it calls the yyLexer's Lex method. Your implementation of that makes no attempt to read a token. Instead, it just returns 0:
func (f *mlex) Lex(lval *yySymType) int {
yyErrorVerbose = true
return 0
}
So from the parser's perspective, it is being given an empty input stream, regardless of what input you might actually have provided. It then attempts to parse this empty input, but your grammar doesn't permit it. The only valid inputs start with the tokens DB or OTHER_DB, and it doesn't see either of those things.
So it produces the error message, detailing exactly what its problem is. (The parser represents the end of input with the internal pseudo-token $end, in case that was confusing you.)

Related

Why does adding an Error() method change program behavior in Go?

The program below prints "2.5"
package main
import (
"fmt"
)
type myFloat64 float64
// func (f myFloat64) Error() string {
// return fmt.Sprintf("Error with %v", f)
// }
func main() {
var a myFloat64 = myFloat64(2.5)
fmt.Printf("%v\n", a)
}
Interestingly, when I uncomment the Error() method, the program no longer prints "2.5"
Question:
Why does adding an Error() method change program behavior? Pointers to the Go language specification explaining this behavior would be much appreciated.
myFloat64 implements the error interface:
type error interface {
Error() string
}
fmt.Println() will consider a as an error value, and print the error message by calling a.Error(), which executes fmt.Sprintf("Error with %v", f). But Sprintf behaves just like Println, it also considers f as an error value and calls Error(). This recursion goes infinitely and causes stack overflow.

trying to create reusable append to struct in go

i am trying to make reusable method / func in go to push valu struct to another slice/ array in struct
i tried like this
import (
"fmt"
)
type ErrorValidate struct {
ErrorKey string
Message string
}
type ValidateMessage struct {
ErrorMessage []*ErrorValidate
}
func (v *ValidateMessage) AddError(err ErrorValidate) {
v.ErrorMessage = append(v.ErrorMessage, &err)
}
func main() {
s1 := *ValidateMessage{}
s1.AddError(&ErrorValidate{"theKey", "string"})
fmt.Println(*s1)
}
got error invalid indirect of ValidateMessage literal (type ValidateMessage)
the link here https://play.golang.org/p/VjdsiZQLroF
on those case i have a func for Validate something and then i tried to push error message on ErrorValidate , but i keep using append in my conditional, i am trying to make it reduce but got error above
There are a couple problems in your code. This one is generating your error (nothing to do with your append, or that method at all):
s1 := *ValidateMessage{}
This is not valid syntax. You probably meant s1 := &ValidateMessage{}.
s1.AddError(&ErrorValidate{"theKey", "string"})
You're trying to pass a *ErrorValidate to a function that takes a ErrorValidate. This should be s1.AddError(ErrorValidate{"theKey", "string"}).

Using default value in golang func

I'm trying to implement a default value according to the option 1 of the post Golang and default values. But when I try to do go install the following error pops up in the terminal:
not enough arguments in call to test.Concat1
have ()
want (string)
Code:
package test
func Concat1(a string) string {
if a == "" {
a = "default-a"
}
return fmt.Sprintf("%s", a)
}
// other package
package main
func main() {
test.Concat1()
}
Thanks in advance.
I don't think what you are trying to do will work that way. You may want to opt for option #4 from the page you cited, which uses variadic variables. In your case looks to me like you want just a string, so it'd be something like this:
func Concat1(a ...string) string {
if len(a) == 0 {
return "a-default"
}
return a[0]
}
Go does not have optional defaults for function arguments.
You may emulate them to some extent by having a special type
to contain the set of parameters for a function.
In your toy example that would be something like
type Concat1Args struct {
a string
}
func Concat1(args Concat1Args) string {
if args.a == "" {
args.a = "default-a"
}
return fmt.Sprintf("%s", args.a)
}
The "trick" here is that in Go each type has its respective
"zero value", and when producing a value of a composite type
using the so-called literal, it's possible to initialize only some of the type's fields, so in our example that would be
s := Concat1(Concat1Args{})
vs
s := Concat1(Concat1Args{"whatever"})
I know that looks clumsy, and I have showed this mostly for
demonstration purpose. In real production code, where a function
might have a dozen of parameters or more, having them packed
in a dedicate composite type is usually the only sensible way
to go but for a case like yours it's better to just explicitly
pass "" to the function.
Golang does not support default parameters. Accordingly, variadic arguments by themselves are not analogous. However, variadic functions with the use of error handling can 'resemble' the pattern. Try the following as a simple example:
package main
import (
"errors"
"log"
)
func createSeries(p ...int) ([]int, error) {
usage := "Usage: createSeries(<length>, <optional starting value>), length should be > 0"
if len(p) == 0 {
return nil, errors.New(usage)
}
n := p[0]
if n <= 0 {
return nil, errors.New(usage)
}
var base int
if len(p) == 2 {
base = p[1]
} else if len(p) > 2 {
return nil, errors.New(usage)
}
vals := make([]int, n)
for i := 0; i < n; i++ {
vals[i] = base + i
}
return vals, nil
}
func main() {
answer, err := createSeries(4, -9)
if err != nil {
log.Fatal(err)
}
log.Println(answer)
}
Default parameters work differently in Go than they do in other languages. In a function there can be one ellipsis, always at the end, which will keep a slice of values of the same type so in your case this would be:
func Concat1(a ...string) string {
but that means that the caller may pass in any number of arguments >= 0. Also you need to check that the arguments in the slice are not empty and then assign them yourself. This means they do not get assigned a default value through any kind of special syntax in Go. This is not possible but you can do
if a[0] == "" {
a[0] = "default value"
}
If you want to make sure that the user passes either zero or one strings, just create two functions in your API, e.g.
func Concat(a string) string { // ...
func ConcatDefault() string {
Concat("default value")
}

Is there any command line in Golang to check syntax error of my go source code & write the errors to a file?

package main
import "fmt"
func plus(a int, b int) int {
return a + b
}
}
func plusPlus(a, b, c int) int {
return a + b + c
}
func main() {
res := plus(1, 2)
fmt.Println("1+2 =", res)
res = plusPlus(1, 2, 3)
fmt.Println("1+2+3 =", res)
}
This is my Go Source code.
gofmt -e my_file.go is working But I am not able to write the errors to a text file.
gofmt will output the errors to the standard error. You can simply redirect the standard error stream of gofmt to a file on unix systems like this:
gofmt -e my_file.go 2>a.txt
Checking it:
more a.txt
Output:
my_file.go:8:1: expected declaration, found '}'

Why GoLang Method gives Compile Error?

I am a trying the Methods in GoLang. I am a newbie so please correct me if I am asking dumb question.
The link says that we can write the Methods as normal Functions. But when I try following code it gives me compile error as
a.sq undefined (type MyFloat has no field or method sq)
The commented lines in following code are working as expected though.
Please help me. Following is my code:
package main
import (
"fmt"
)
type MyFloat float64
func sq (f MyFloat) string {
return fmt.Sprintln("The square is: ", f*f)
}
/*func (f MyFloat) sq() string {
return fmt.Sprintln("The square is: ", f*f)
}*/
func main() {
a := MyFloat(2.0)
fmt.Println(a.sq())
}
You are declaring sq as a function, not a method. If you want to attach sq to MyFloat, you should declare it like:
func (f MyFloat) sq() string {
return fmt.Sprintln("The square is: ", f*f)
}
This way you will be able to do a.sq().

Resources